Is there a way to make Rails ActiveRecord attributes private?

老子叫甜甜 提交于 2019-11-28 06:16:33

Jordini was most of the way there

Most of active_record happens in method_missing. If you define the method up front, it won't hit method_missing for that method, and use yours in stead (effectively overwriting, but not really)

class YourModel < ActiveRecord::Base

  private

  def my_private_attribute
    self[:my_private_attribute]
  end

  def my_private_attribute=(val)
    write_attribute :my_private_attribute, val
  end

end

well, you could always override the methods...

class YourModel < ActiveRecord::Base

  private

  def my_private_attribute
    self[:my_private_attribute]
  end

  def my_private_attribute=(val)
    self[:my_private_attribute] = val
  end

end

Stumbled upon this recently. If you want private writing and reading and public reading something like this

class YourModel < ActiveRecord::Base

  attr_reader :attribute

  private

  attr_accessor :attribute


end

seems to work fine for me. You can fiddle with attr_reader, attr_writer and attr_accessor to decide what should be exposed and what should be private.

You can make an existing method private:

YourClass.send(:private, :your_method)
Andrew Kozin

For me methods from both Otto and jordinl are working fine and make rspec for object of Class to pass:

object.should_not respond_to :attribute

But when I use jordinl method, I have a deprecation message to not write to database directly, but use attr_writer instead.

UPDATE:

But the truly "right" metod to do it turns out to be simple. Thanks to Mladen Jablanović and Christopher Creutzig from here. To make predefined method private or protected... simply redefine it:

Class Class_name

  private :method_name
  protected :method_name_1
end

What's important, you needn't rewrite previously defined method's logic.

Making the setting private does generate ActiveRecord error.

I put access control code in the overwritten method of the public setter by checking the caller:

def my_private_attribute=(val)
  if (caller.first.include?('active_record/base.rb') || caller.first.include?('app/models/myclass.rb'))
    self[:my_private_attribute] = val
  else
     raise Exception.new("Cannot set read-only attribute.")
  end
end

I don't think there is 100% reliable way to do this. It's also worth checking the most popular ways to access attributes:

http://www.davidverhasselt.com/set-attributes-in-activerecord/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!