2

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

我得到的错误如下:

ruby-1.9.3-p0 :005 > User.new :username => "johnsmith", :email => "johnsmith@gmail.com", :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
4

1 回答 1

1

不完全确定您正在尝试做什么或这个 mass_assignment_authorizer 的目的是什么。似乎有更简单的方法来防止大规模分配。话虽如此,我阅读了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 => "johnsmith@gmail.com", :password => "changethis")

根据您需要根据权限访问多少属性,您最好跳过此模块,因为它需要一些额外的工作来实现。如果它只是一个或两个模型上的几个属性,你最好用你自己的方法和 attr_accessible 手动实现这个功能。试着阅读这篇关于 ruby​​ 访问器的文章,看看你是否可以在没有这个插件的情况下获得想要的结果?

于 2011-12-28T22:11:59.650 回答