Reputation: 5148
According to the rails-cast #237, dynamic attributes were to be easily implemented. Although I have run into some errors when trying to create an object in the rails console. Please advise.
The error I am getting is as follows :
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
Upvotes: 2
Views: 1667
Reputation: 5716
Not entirely sure exactly what it is you're trying to do or what the purpose of this mass_assignment_authorizer would be. Seems like there are easier ways to protect against mass assignment. That being said, I read the last couple paragraphs of the railscast, and it appears as though once you have this initializer, you can't pass any arguments into the initializer when creating an object. Even if you could, it wouldn't set the attributes...
In the controller we also need to apply the accessible option to the create action. If we just apply it like this then it will not work.
@article = Article.new(params[:article])
@article.accessible = :all if admin?
The reason that this doesn’t work is that the mass assignment happens in the new call so by the time we’ve set accessible it’s too late. We need to separate creating a new Article from assigning its attributes and slip the call to accessible in between the two.
So it looks to me like in order to set the attributes for one of your models now you need to first create it, then set accessible to be :all
on the class, then manually assign the attributes you want, like such:
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")
Depending on how many attributes you need to have accessible based on permissions, you may be better off skipping this module since it is a little bit of extra work to implement. If it's only a few attributes on one or two models you may be better off just implementing this functionality by hand with your own methods and attr_accessible. Try reading this article about ruby accessors to see if you can get the desired result without this plugin perhaps?
Upvotes: 1