开发者

Why doesn't :readonly => true work on a belongs_to association?

I have the fo开发者_StackOverflowllowing model:

class Question < ActiveRecord::Base

  belongs_to :user, :readonly => true

end

I would expect that the :readonly => true attribute would prevent the user from being changed i.e.

# assume we've set up user_1, user_2 and question 
# and that question.user == user_1

question.user = user_2
question.save
question.reload 
question.user == user_2 # true - why?

Why is this true - I expected that :readonly=> true would prevent this attribute from being changed after initial creation? If it doesn't then what does the :readonly option actually do?

EDIT

Using attr_readonly will give the non-changeability (immutability?) that I was looking for.

class Question < ActiveRecord::Base

  belongs_to :user
  attr_readonly :user_id

end

The only problem with it is that it never raises an exception when you try to change the attribute so it's easy to get bugs out of silent fails.


From the doc,

:readonly
    If true, the associated object is readonly through the association.

So I suppose that prevents you from doing things such as

question.user.name = 'Hacked'

But let you continue to modify the relation itself.


like @christianblais said, it only affects changing the properties of the object, not replacing it.

to prevent that redefine user= in your model

class Question < ActiveRecord::Base

  belongs_to :user, :readonly => true

  def user=(new_user)
    if self.user.nil?
      write_attirbute :user_id , new_user.id
    else 
      return false # or raise your prefrence 
    end
end

or you could eliminate the conditional and make it always raise an exception, then initialize it with new or create, / update attributes


as far as belongs_to refers to an id-column def user=(new_user) will not fire but def user_id=(new_user_id) will do! So the example would be:

class Question < ActiveRecord::Base

  belongs_to :user, :readonly => true

  def user_id=(new_user_id)
    if self.user.nil?
      write_attribute :user_id , new_user_id
    else 
      return false # or raise your preference 
    end
  end
end

Tested here on Rails4 and ruby 1.9.3

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜