Passing in a hash to a class without using an initialization method

I was under the, apparently incorrect, impression that when I pass a hash into a class the class requires an initialization method like this:

class Dog

  attr_reader :sound

  def initialize(params = {})
    @sound = params[:sound]
  end

end

dog = Dog.new({sound:"woof"})
puts dog.sound

But I've run into a bit of code (for creating a password digest) that works within a rails application that doesn't use an initialization method and seems to work just fine and it's kind of confuses me because when I try this anywhere else it doesn't seem to work. Here is the sample code that works (allows me to pass in a hash and initializes without an initialization method):

class User < ActiveRecord::Base
  attr_reader :password
  validates :email, :password_digest, presence: true
  validates :password, length: { minimum: 6, allow_nil: true }
  def password=(pwd)
    @password = pwd
    self.password_digest = BCrypt::Password.create(pwd)
  end
end

NOTE: In the create action I pass in a hash via strong params from a form that, at the end of the day, looks something like this {"email"=>"joeblow@gmail.com", "password"=>"holymolycanoli”}

In this bit of code there is no initialization method. When I try something like this (passing in a hash without an initialization method) in pry or in a repl it doesn't seem to work (for instance the following code does not work):

class Dog

  attr_reader :sound

  def sound=(pwd)
    @sound = pwd
  end

end

dog = Dog.new({sound:"woof"})
puts dog.sound

The error I get is:

wrong number of arguments (1 for 0)

Is it rails that allows me to pass in hashes like this or ActiveRecord? I'm confused as to why it works within rails within this context but generates an error outside of rails. Why does this work in rails?


If you look at the top you have this:

class Dog < ActiveRecord::Base

This causes your class Dog to inherit from ActiveRecord::Base when it does so it gains a bunch of methods that allows you to set things up.

Now when you call for example:

Dog.create(password: 'some_password', username: 'some_username')

Your calling a method on the class object that then returns an instance of the class.

so taking your example

class Dog

  attr_reader :sound

  def sound=(pwd)
    @sound = pwd
  end

  def self.create data_hash
   new_dog = self.new #create new instance of dog class
   new_dog.sound = data_hash[:sound] #set instance of dog classes sound
   new_dog # return instance of dog class
  end

end

It's essentially what we would term a factory method, a method that takes in data and returns an object based on that data.

Now I have no doubt that ActiveRecord::Base is doing something more complicated than that but that is essentially what it's doing at the most basic of levels.

I'd also like to point out that when inheriting from ActiveRecord::Base your also inheriting its 'initialize' method so you don't have to set one yourself. The class knows what attribute methods to create based on the schema you set when you did the DB migrations for a table that matches (through rail's conventions) the class.


A lot of things happen when you subclass ActiveRecord::Base. Before looking at other issues I'm guessing that Dog is a rails ActiveRecord model and you just forgot to add

class Dog < ActiveRecord::Base
链接地址: http://www.djcxy.com/p/60960.html

上一篇: 强制第一个散列和数组元素位于rubocop中的同一行上

下一篇: 在不使用初始化方法的情况下将哈希传递给类