2011-12-28 52 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