为什么attr_accessor在Ruby on Rails中破坏了这个模型中的现有变量?

最近我被这种情况所困扰,确切地知道发生了什么事情是有用的,所以其他人避免这种错误。

我有一个模型用户,其架构如下:

create_table "users", :force => true do |t| t.string "user_name" t.string "first_name" t.string "last_name" t.string "email" t.string "location" t.string "town" t.string "country" t.string "postcode" t.boolean "newsletter" 

在类user.rb中,我有三个方法的attr_accessor:

 class User < ActiveRecord::Base # lots of code attr_protected :admin, :active # relevant accessor methods attr_accessor :town, :postcode, :country end 

现在在我的用户控制器中,如果我有以下方法:

 def create @user = User.new params[:user] end 

当我尝试使用此params哈希中的内容创建新用户时:

  --- !map:HashWithIndifferentAccess # other values country: United Kingdom dob(1i): "1985" dob(2i): "9" dob(3i): "19" town: london 

返回的对象具有countrytownpostcode值的空字符串,如此。

 (rdb:53) y user1 --- !ruby/object:User attributes: # lots of attributes that aren't relevant for this example, and are filled in okay postcode: country: town: 

我可以说attr_accessor方法正在破坏Active Record现有的访问器方法,因为当我把它们拿出来时一切正常,所以解决方案相当简单 – 只需将它们取出即可。

但是到底发生了什么呢?

我在这里查看Active Record的Rails API文档 ,这里有关于attr_accessor Ruby自己的文档 ,但我仍然对attr_accessor如何破坏这里的东西略显模糊。

任何能够摆脱一些光线来阻止其他一些可怜的灵魂犯下这种罪恶?

将attr_accessor添加到类时,它会在其上定义两个方法,例如User#postcode和User#postcode =。

如果访问者的名称等于模型属性的名称,则事情会中断(如果您不小心)。 当您为模型指定属性时,会调用User#postcode =,在您的情况下,除了

 @postcode = value 

因此,该值只存储在实例变量中,不会出现在属性哈希中。

而在正常情况下(没有访问器),这将转向method_missing并最终触发类似的东西

 write_attribute(:postcode, value) 

然后它会出现在模型的属性中。 希望有道理。

为什么在第一时间你使用attr_accessor :town, :postcode, :country ? Active Record为您设置了setter / getter方法。 只要放弃这一行,事情应该有效。

您可能希望在ActiveRecord模型上使用attr_accessible来启用属性的批量分配。 您不需要attr_accessor因为已经为模型属性定义了getters / setter。