2011-12-28 63 views
2

根据rails-cast #237,动态属性很容易实现。虽然我试图在rails控制台中创建一个对象时遇到了一些错误。请指教。动态attr_accessible in rails

我得到的错误如下:

ruby-1.9.3-p0 :005 > User.new :username => "johnsmith", :email => "[email protected]", :password => "changethis" 
ArgumentError: wrong number of arguments (1 for 0) 
    from /Volumes/Terra-Nova/jwaldrip/Sites/theirksome/config/initializers/accessible_attributes.rb:6:in `mass_assignment_authorizer' 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/activemodel-3.1.3/lib/active_model/mass_assignment_security.rb:209:in `sanitize_for_mass_assignment' 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.1.3/lib/active_record/base.rb:1744:in `assign_attributes' 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.1.3/lib/active_record/base.rb:1567:in `initialize' 
    from (irb):5:in `new' 
    from (irb):5 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.1.3/lib/rails/commands/console.rb:45:in `start' 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.1.3/lib/rails/commands/console.rb:8:in `start' 
    from /Volumes/Terra-Nova/jwaldrip/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.1.3/lib/rails/commands.rb:40:in `<top (required)>' 
    from script/rails:6:in `require' 
    from script/rails:6:in `<main>' 

/models/user.rb:

class User < ActiveRecord::Base 

    # Attributes 
    attr_accessible :username, :email, :password, :password_confirmation, :is_admin 
    attr_accessor :password 

    # Callbacks 
    before_save :encrypt_password 

    # Relationships 
    has_many :irks 

    # Validation 
    validates_confirmation_of :password 
    validates_presence_of :password, on: :create 
    validates :password, presence: true, length: { in: 3..20 } 

    validates :username, presence: true, uniqueness: true, length: { in: 3..20 } 
    validates :email, presence: true, email: true, uniqueness: true 

    # User Authentication 
    def self.authenticate(email, password) 
     user = find_by_email(email) 
     if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt) 
      user 
     else 
      nil 
     end 
    end 

    # Password Encryption 
    def encrypt_password 
     if password.present? 
      self.password_salt = BCrypt::Engine.generate_salt 
      self.password_hash = BCrypt::Engine.hash_secret(password, password_salt) 
     end 
    end 
end 

/config/initializers/accessible_attributes.rb:

class ActiveRecord::Base 
    attr_accessible 
    attr_accessor :accessible 

    private 

    def mass_assignment_authorizer 
     if accessible == :all 
      self.class.protected_attributes 
     else 
      super + (accessible || []) 
     end 
    end 
end 

回答

1

不完全确定你正在尝试做什么或者这个mass_assignment_authorizer的目的是什么。似乎有更简单的方法来防止大规模分配。这就是说,我读了最后一个couple paragraphs of the railscast,它看起来好像有了这个初始值设定项,在创建一个对象时就不能将任何参数传递给初始值设定项。即使可以,它也不会设置属性...

在控制器中,我们还需要将可访问选项应用于创建操作。如果我们只是像这样应用它,那么它将不起作用。

@article = Article.new(params[:article]) 
@article.accessible = :all if admin? 

的原因,这是行不通的是,质量分配发生在新的调用,这样的时候,我们已经设置访问为时已晚。我们需要分开创建一个新的文章,以指定其属性,并将呼叫转移到两者之间。

所以它看起来对我来说,以设置您的机型之一的属性,现在你需要首先创建它,然后设置访问是:all的类,然后手动指定你想要的属性,如例如:

u = User.create 
u.accessible = :all if current_user.is_admin? # or whatever the conditional is for the admin user 
u.update_attributes(:username => "johnsmith", :email => "[email protected]", :password => "changethis") 

根据您需要多少属性,基于权限有访问,你可能会更好跳过这个模块,因为它是额外的工作一点点实现。如果只有一个或两个模型中的几个属性,那么使用自己的方法和attr_accessible手动实现此功能可能会更好。尝试阅读this article about ruby accessors以查看是否可以在没有此插件的情况下获得理想的结果?

+0

我试图完成的唯一事情是根据您的权限使某些属性可访问。又名当你拥有这个对象时,或者你是一个管理员。 – 2011-12-29 20:54:58

+0

看完railscast并重新阅读说明后,我改变了我的看法。我认为这是一个明智的解决方案。这就是说,它看起来好像railscast已经过时并且不兼容'rails 3.1'。 [我会阅读attr_accessible为ActiveRecord的版本的rails你正在使用的文档](http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.Mtml#method-i-attr_accessible)。看起来它已经变得更容易了,您正在使用的模块是不必要的,因为您现在可以定义哪些属性可以在每个角色的基础上访问。 – Batkins 2011-12-29 21:54:51