Can't mass-assign protected attributes attr_accessor and attr_accessible - ruby

in rails 2.3.11, I have below in model
attr_accessor :person_id
and in controller
#project.person_id = current_user.id
now, I am converting this in rails 3.2.11 and I am getting
Can't mass-assign protected attributes: person_id
so I changed in model, I removed :person_id from attr_accessor and add below line
attr_accessible :person_id
but I am uisng person_id in controller, here it is
#project.person_id = current_user.id
I am getting this now
NoMethodError in ProjectsController#create
undefined method `person_id=' for #<Project:0x19cc51a>
any idea or help, How can I fix this? How can I handle both attr_accessor & attr_accessible?

attr_accessor :person_id and attr_accessible :person_id are not the same.
attr_accessor is the Ruby method. In short its shortcut for methods:
def person_id
#person_id
end
def person_id=(value)
#person_id = value
end
attr_accessible is the Rails method. Which gets list of attributes allowed to be mass-assigned. You can read about here.
Thus in your case you need both of them.
attr_accessor :person_id
attr_accessible :person_id

Related

Validation not working on Class that extends ActiveModel::Naming, include ActiveModel::Validations

I and new to ruby and rails; I have the below ruby class definition that I am using in my rails 3 app. This class is simply used as a property container for contact information populated in my view on submit (form_for). I read a post where you can use ActiveModel directly apart from ActiveRecord, to perform validation, so I am trying it. I am getting the following exception when I check to see if the the object is valid? in my controller on postback. I assumed that valid? would be available being that I included ActiveModel::Validations; perhaps I am doing a few other things a$$ backwards. Any help would be appreciated:
undefined method `valid?' for #
Here's my class definition, further down is how I am handling it in my controller action:
require 'active_model'
class ContactModel
extend ActiveModel::Naming
include ActiveModel::AttributeMethods
include ActiveModel::Validations
include ActiveModel::Conversion
validates_presence_of :first_name, :last_name, :email_address, :email_address_confirmed, :subject, :contact_message
attr_accessor :first_name, :last_name, :email_address, :email_address_confirmed,
:telephone_number, :subject, :contact_message
Just messing around testing.
validates_each :first_name, :last_name do |record, attr, value|
record.errors.add attr, 'starts with z.' if value.to_s[0] == z
end
...
end
In my controller/action...
def send_email
##contact_model = ContactModel.new().initialize_copy(params[:contact_model])
#contact_model = params[:contact_model].dup
respond_to do |format|
if (#contact_model.valid?)
# Tell the UserMailer to send a welcome Email after save
ContactMailer.contact_email(#contact_model).deliver
format.html { redirect_to(#contact_model, notice: 'Email successfully sent.') }
format.json { render json: #contact_model, status: :created, location: #contact_model }
else
# What to do here?
end
end
end
In your controller you are setting #contact_model to a hash, params[:contact_model], and then calling valid? on it. You need create an instance of ContactModel and call valid on that. Like so:
#contact_model = ContactModel.new(params[:contact_model])
if (#contact_model.valid?)
...
I see commented out code that calls ContactModel.new(), but that's not how you want to do it anyway. Also, there is no reason to dup() or initialize_copy() on the params stuff.

ActiveModel::MassAssignmentSecurity::Error in ApiUsersController#create

I am not able to create new api_user. Everytime I try to create it I get
Can't mass-assign protected attributes: utf8, authenticity_token, api_user, commit, action, controller
here's my model api_user.rb
class ApiUser < ActiveRecord::Base
attr_accessible :api_key, :count, :email, :name, :organization
end
controller api_users_controller.rb
class ApiUsersController < ApplicationController
#skip_before_filter :verify_authenticity_token
def new
#api_user = ApiUser.new
end
def create
#api_user=ApiUser.create(params)
render :text=>"#{#api_user.id}"
end
def destroy
#api_user=ApiUser.find(params[:id])
#api_user.destroy
render :text=>"Deleted successfully"
end
end
I am using Ruby 1.9.2 and Rails 3.2.3
In order to create the ApiUser, you should use only the correct params:
#api_user=ApiUser.create(params[:api_user])
not all the paramshash

"undefined method" for a rails model

I am using Devise with rails and i want to add a method "getAllComments", so i write this :
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :city, :newsletter_register, :birthday, :postal_code,
:address_complement, :address, :lastname, :firstname, :civility
has_many :hotels_comments
class << self # Class methods
def getAllComments
true
end
end
end
And in my controller :
def dashboard
#user = current_user
#comments = #user.getAllComments();
end
And when i go to my url, i got
undefined method `getAllComments' for #<User:0x00000008759718>
What i am doing wrong?
Thank you
Because getAllComments is a class method and you are attempting to access it as an instance method.
You either need to access it as:
User.getAllComments
or redefine it as an instance method:
class User < ActiveRecord::Base
#...
def getAllComments
true
end
end
def dashboard
#user = current_user
#comments = #user.getAllComments
end
As I can see, you make getAllComments as class method through addition it to eigenclass. And you try to call this method from instance.
Content of class << self means class method. It could be shortened as def self.getAllComments
You should call it User.getAllComments and not #user.getAllComments
The getAllComments() method that you wrote is a class method
So the correct way to call the methods is
#comments = User.getAllComments
But if you really want to scope the getAllComments to the current user, I recommend you write an instance method
class User < ActiveRecord::Base
..
def getAllComments
// comments implementation
end
So that way you can access the getAllComments method like so:
#user = current_user
#comments = #user.getAllComments

Override a Mongoid model's setters and getters

Is there a way to override a setter or getter for a model in Mongoid? Something like:
class Project
include Mongoid::Document
field :name, :type => String
field :num_users, type: Integer, default: 0
key :name
has_and_belongs_to_many :users, class_name: "User", inverse_of: :projects
# This will not work
def name=(projectname)
#name = projectname.capitalize
end
end
where the name method can be overwritten without using virtual fields?
better use
def name=(projectname)
super(projectname.capitalize)
end
the method
self[:name] = projectname.capitalize
can be dangerous, cause overloading with it can cause endless recursion
def name=(projectname)
self[:name] = projectname.capitalize
end
I had a similar issue with needing to override the "user" setter for a belongs_to :user relationship. I came up with this solution for not only this case but for wrapping any method already defined within the same class.
class Class
def wrap_method(name, &block)
existing = self.instance_method(name)
define_method name do |*args|
instance_exec(*args, existing ? existing.bind(self) : nil, &block)
end
end
This allows you to do the following in your model class:
wrap_method :user= do |value, wrapped|
wrapped.call(value)
#additional logic here
end

Rails Model callback: Passing field as parameter to callback classes?

I want to implement before_validaton callback in a separate class so that it can be reused by multiple model classes.
Here in callback i want to strip field passed as parameter but i am not sure how to pass parameter to callback class. Also i want to pass this as reference rather than by value(not sure if this concept is in Ruby Rails). I am following the link http://guides.rubyonrails.org/active_record_validations_callbacks.html#callback-classes
Here is code which is not completely correct, please help for same
class StripFieldsCallback
def self.before_validation(field)
field = field.strip
end
end
class User < ActiveRecord::Base
validates_uniqueness_of :name, :case_sensitive => false
validates_length_of :name, :maximum => 50
before__validation StripFieldsCallback(name)
end
If i define method in model in itself rather than defining in separate callback class code is like this (which works fine)
class User < ActiveRecord::Base
validates_uniqueness_of :name, :case_sensitive => false
validates_length_of :name, :maximum => 50
before__validation :strip_blanks
protected
def strip_blanks
self.name = self.name.strip
end
end
Of course it is not good to replicate methods in all of models so i want to define method in callback classes.
You may do this or use normalize_attributes gem
module StripFieldsCallback
def before_validation_z(field)
write_attribute(field, read_attribute(field).strip) if read_attribute(field)
end
end
class User < ActiveRecord::Base
include StripFieldsCallback
before_validation lambda{|data| data.before_validation_z(:name)}
end

Resources