为什么 attr_accessor 会破坏 Ruby on Rails 模型中的现有变量? [英] Why does attr_accessor clobber the existing variables in this model in Ruby on Rails?
问题描述
我最近被这件事咬了一口,准确地知道发生了什么事情会导致这种情况发生,这样其他人就可以避免这个错误.
I was bitten by this recently, and it'd be useful to know precisely what's happening to make this happen, so others avoid this mistake.
我有一个模型用户,其架构如下:
I have a model User, with a schema like so:
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:
In the class user.rb, I have a attr_accessor for three methods:
class User < ActiveRecord::Base
# lots of code
attr_protected :admin, :active
# relevant accessor methods
attr_accessor :town, :postcode, :country
end
现在在我的用户控制器中,如果我有以下方法:
Now in my user controller, if I have the following method:
def create
@user = User.new params[:user]
end
当我尝试使用此参数哈希中的内容创建新用户时:
When when I try to create a new user with the contents in this params hash:
--- !map:HashWithIndifferentAccess
# other values
country: United Kingdom
dob(1i): "1985"
dob(2i): "9"
dob(3i): "19"
town: london
返回的对象对于country
、town
和postcode postcode
值有空字符串,就像这样.
The returned object has empty strings for the country
, town
and postcode postcode
values, like so.
(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 现有的访问器方法,因为当我将它们取出时一切正常,所以解决方案相当简单 - 取出它们即可.
I can tell that the attr_accessor methods are clobbering Active Record's existing accessor methods, because when I take them out all works fine, so the solution is fairly straightforward - just take them out.
但是这里究竟发生了什么?
我在 中查看这里Active Record 的 Rails API 文档,在 Ruby 自己的关于 attr_accessor
的文档,但我对 attr_accessor
在这里破坏的方式仍然有些模糊.
I'm looking here in the Rails API docs for Active Record, and here in Ruby's own docs about attr_accessor
, but I'm still slightly hazy about how attr_accessor
is breaking things here.
有没有人能够阻止其他一些可怜的灵魂犯规?
Any able to shed some light to stop some other poor soul falling foul of this?
推荐答案
当你向一个类添加一个 attr_accessor 时,它定义了两个方法,例如用户#postcode 和用户#postcode=.
When you add an attr_accessor to a class, it defines two methods on it, e.g. User#postcode and User#postcode=.
如果访问器的名称等于模型属性的名称,事情就会中断(如果你不小心的话).当您为模型分配属性时, User#postcode= 被调用,在您的情况下,除了
If the name of the accessor is equal to a name of a model attribute, things break (if you're not careful). When you assign attributes to the model, User#postcode= is called and in your case it does nothing except
@postcode = value
所以该值只是存储在一个实例变量中,并没有出现在属性哈希中.
So the value just gets stored in an instance variable and doesn't appear in the attributes hash.
而在正常情况下(没有访问器),这将转到 method_missing 并最终触发类似
Whereas in a normal scenario (without an accessor) this would go to method_missing and eventually trigger something like
write_attribute(:postcode, value)
然后它会出现在您模型的属性中.希望这是有道理的.
And then it would appear in your model's attributes. Hope that makes sense.
这篇关于为什么 attr_accessor 会破坏 Ruby on Rails 模型中的现有变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!