update attributes cause mass assignment exception, even with attr_accessible - ruby-on-rails

I receive the following error even though I have the fields to be updated in attr_accessible
Can't mass-assign protected attributes: utf8, _method, authenticity_token, profile, commit, action, controller, id
I'm guessing the other attributes that I don't want to save are raising the exception, but how can I filter them out?
this is the params hash
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"1aabj2DxleZoDu/U0SzGXSZrPcesRKXkIXTRVbk9f0A=",
"profile"=>{"name"=>"Aaron Dufall",
"company"=>"Supreme Windows",
"location"=>"",
"professional_bio"=>""},
"commit"=>"Update",
"id"=>"1"}
profiles_controller.rb
class ProfilesController < ApplicationController
respond_to :html
def edit
#profile = Profile.find(params[:id])
respond_with #profile
end
def update
#profile = Profile.find(params[:id])
if #profile.update_attributes(params)
flash[:success] = "Profile sucessfully updated"
redirect_to root_path
else
flash[:error] = "Profile failed to update"
render 'edit'
end
end
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :name, :company, :location, :professional_bio
end

In your controller you should use
if #profile.update_attributes(params[:profile])
This will filter only the attributes which are under "profile" key on params.

You may want to consider using :without_protection - It will skip mass-assignment security.
Ie:
User.new({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
re: http://apidock.com/rails/ActiveRecord/Base/new/class

Related

undefined method `build_profile' for #<User:0x000000035b9ae8>

I can't figure out the problem with my code. I'm trying to add a profile to my user. For this I get my user ID and attach this to my profile in a DB. However after submitting the form it gives the following error: NoMethodError in ProfilesController#create
class ProfilesController < ApplicationController
# GET to /users/:user_id/profile/new
def new
#profile = Profile.new
end
# POST to /users/:user_id/profile
def create
# Ensure that we have the user who is filling out form
#user = User.find(params[:user_id])
# Create profile linked to this specific user
#profile = #user.build_profile( profile_params )
if #profile.save
flash[:success] = "Profile updated!"
redirect_to root_path
else
render action: :new
end
end
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking)
end
end
Your models need to be some thing like this... I assume you are missing a has_many or belongs_to in the user modal.
class User
has_many :profile
# or belongs_to :profile
end
class Profile
belongs_to :user
# or has_many :users
end
Give your modals if it doesn't work, we can fix it up.
try to replace
#user = User.find(params[:user_id])
#profile = #user.build_profile( profile_params )
by
#profile.user_id = current_user.id
for user_id it depend how you named your user id foreign key
You may do
def create
#profile = Profile.new(profile_params)
if #profile.save
flash[:success] = "Profile updated!"
redirect_to root_path
else
render action: :new
end
end
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking, :user_id)
end
Or
def profile_params
params.require(:profile).permit(:first_name, :last_name, :phone_number, :contact_email, :banking).merge!(user: current_user)
end
Regarding the error "NoMethodError in ProfilesController#create" it may happen because it is not declared in the routes.rb or it does a HTTP Get instead of a Post.
in the routes.rb file,
resources :users do
resources :profiles
end
http://guides.rubyonrails.org/routing.html#nested-resources

before_validation method not working

I am a newB in rails and I am working on a project and wanted to remove trailing and leading white spaces from username and email. So I created a method in user model
class User < ActiveRecord::Base
include CarrierWave::MiniMagick
#removes the white spaces before validating the data
before_validation :strip_whitespace, :only => [:name,:email]
#data validations
validates :email, :presence =>true, :uniqueness => {case_sensitive: false}, :format => { :with=> /([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)/, :message => "please enter a valid e-mail" }
validates :name, :presence=>true
validates :password ,:presence =>true, :confirmation=> true #, :length =>{ :minimum=>6, :maximum=>30}, :format=>{:with=>/(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,30}/}
#for the image
mount_uploader :image, ImageUploader
#for the password
has_secure_password
#associations
has_many :issues
has_many :comments
end
def strip_whitespace
self.email = self.email.squish
self.name = self.name.squish
end
when I enter user information in Users.create action, the leading and trailing spaces are removed, But when I login from my sessions controller, the leading and trailing spaces are not removed and hence it shows me an error.
Please help
Code for the users controller
class UsersController < ApplicationController
before_action :not_logged_in?, :only => [:new]
def new
#user=User.new
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
RegistrationsMailer.welcome_email(#user).deliver
flash[:success] = 'you are successfully registered'
redirect_to :controller => 'users' , :action => 'show', :id => #user.id
else
render 'new'
end
end
def show
#user=User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
render 'edit'
end
end
protected
def user_params
params.require(:user).permit(:name,:email,:password,:image)
end
end
code for sessions controller
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_email(params[:sessions][:email])
if #user && #user.authenticate(params[:sessions][:password])
sign_in #user
redirect_to #user
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end
def destroy
end
end
Please help
According to When does Validation happen?
The following methods trigger validations, and will save the object to the database only if the object is valid:
create
create!
save
save!
update
update!
When you are creating or destroying a new session, you don't actually call any of those methods on the User model so validations won't be called.
But since your database has the squished values, you need to modify your create action in the SessionsController to squish the passed in params.
def create
#user = User.find_by_email(params[:sessions][:email].squish)
if #user && #user.authenticate(params[:sessions][:password].squish)
sign_in #user
redirect_to #user
else
flash.now[:error] = 'Invalid email or password'
render 'new'
end
end

Setting an id as a default foreign key in rails

I am having challenges assigning a current user a role in a team the user is creating. I want to assign the user that creates the team the role of the captain which could be changed later.
I'm currently using the create_asociation method that comes with has_one relationship, as this instantiates the values of the associated model, which i want to be instantiated with the current user but get the error Can't mass assign protected attribute: captain. Captain is a self join model with user as i will like to use captain.teammates and team.captain.
Below are the models involved.
User and Captain Model
class User < ActiveRecord::Base
has_one :profile
has_many :teammates, :class_name => "User", :foreign_key => "captain_id"
belongs_to :captain, :class_name => "User"
belongs_to :team
# before_create :build_profile
after_create :build_default_profile
accepts_nested_attributes_for :profile
attr_accessible :email, :password, :password_confirmation, :profile_attributes, :captain_id
def build_default_profile
Profile.create(user_id: self.id)
end
has_secure_password
before_save { email.downcase! }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Team Model
class Team < ActiveRecord::Base
has_many :profiles, through: :users
has_one :captain, :class_name => "User", foreign_key: :captain_id
has_one :result, as: :result_table
attr_accessible :teamname, :color, :result_attributes, :captain_attributes
after_create :build_result_table
after_create :build_default_captain
accepts_nested_attributes_for :profiles
accepts_nested_attributes_for :captain
accepts_nested_attributes_for :result
def build_result_table
Result.create(result_table_id: self.id, result_table_type: self.class.name)
end
def build_default_captain
# Team.captain = User
# Captain.create(team_id: self.id, captain_id: user.id)
end
end
User Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save!
sign_in #user
flash[:success] = "Welcome to the JHDC Mini Olympics Web Application; Thanks for singing Up"
redirect_to user_profile_path(#user, #profile)
else
flash[:error_messages]
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def index
#users = User.paginate(page: params[:page])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile Updated"
redirect_to user_profile_path(#user, #profile)
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
end
Team Controller
class TeamsController < ApplicationController
def new
#team = Team.new
end
def create
#team = Team.new(params[:team])
#captain = #team.create_captain(captain: current_user)
if current_user.admin?
if #team.save!
flash[:success] = "Team created."
redirect_to #team
else
flash[:error_messages]
render 'new'
end
else
flash[:error] = "Sorry, you don't have the authority to create a Team"
redirect_to current_user
end
end
def index
#teams = Team.paginate(page: params[:page])
end
def show
#team = Team.find(params[:id])
end
def edit
if current_user.admin?
#team = Team.find(params[:id])
else
flash[:error] = "Sorry you dont have the authourity to edit a Team"
redirect_to current_user
end
end
def update
#team = Team.find(params[:id])
if #team.update_attributes(params[:team])
flash[:success] = "Team Updated"
redirect_to #team
else
render 'edit'
end
end
def destroy
Team.find(params[:id]).destroy
flash[:success] = "Team is deleted."
redirect_to teams_url
end
private
def team_params
params.require(:team).permit(:teamname, :color)
end
end
The admin is currently a way i'm using to restrict the user that can create a team but i plan to use gems like declarative authorization to create role based authorization. Thanks
The error you are getting is because the attribute :captain is not declared as attr_accessible
Either set the attribute :captain in your list of attr_accessible for the User model, or change the code form
Captain.create(team_id: self.id, captain_id: user.id)
to
captain = Captain.new
captain.team_id = self.id
captain.captain_id = user.id
captain.create
in this way, the attribute won't be set by mass-assignment and won't raise the error
Edited
After checking your code twice, just realized that you don't have a Captain model, actually :captain is a relation for the user and a relation from the Team to the User.
So on Team model, take off the build_default_captain stuff and the after_create :build_default_captain, I would say to replace with something like
after_save :set_default_captain
def set_default_captain
if captain_id_changed?
profiles.each do |user|
user.captain = captain
user.save
end
end
end
so every time the captain_id change for the model, you change the captain_id of all its profiles (users)
Then on the Team controller, on the action create, instead of
#team = Team.new(params[:team])
#captain = #team.create_captain(captain: current_user)
do something like
#team = Team.new(params[:team])
#team.captain = current_user
if current_user.admin?
if #team.save!
current_user.update_attribute(:team_id, #team.id)
flash[:success] = "Team created."
redirect_to #team
else
flash[:error_messages]
render 'new'
end
else
flash[:error] = "Sorry, you don't have the authority to create a Team"
redirect_to current_user
end
so on the last part of the code, you set the captain of the team to the current user and set the user team to the current team once its saved, you can also improve the code with current_user.build_team to avoid saving current_user.update_attribute

Cannot retrieve attr_accessor in Rails 4

I'm working on a Ruby on Rails project and I have two models:
1. User
2. Merchant
their relationships are:
User has_one :merchant
Merchant belongs_to :user
then in my user.rb
attr_accessor :merchant_name
after_create :create_merchant
def create_merchant
create_merchant(name: merchant_name)
end
In my user's form:
= form_for #user do |f|
= f.text_field :merchant_name
= f.text_field :email
= f.text_field :password
the problem is the user and a merchant has been created but the merchant's name is nil
In my Account::RegistrationsController
class Account::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
account_users_path
end
private
def registration_params
params.require(:user).permit(:merchant_name)
end
end
I'm getting this error:
Processing by Account::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ht8vHG8I4bz2ylt+mtLC7hilQnK3VnYtcHgSNv8nSeg=", "user"=>{"merchant_name"=>"Zara 123", "email"=>"allen.chun#hotmail.com",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign Up"}
Unpermitted parameters: merchant_name
I wouldn't override the create_merchant method if I were you, try something like this:
after_create -> { create_merchant!(:name => self.merchant_name) }
and make sure your merchant_name is permitted in the users controller, something like this:
def create
#user = User.new(user_params)
if #user.save
redirect_to #user
else
render :new
end
end
private
def user_params
params.require(:user).permit(:merchant_name, :email, :password, :password_confirmation)
end
Perhaps it should be
attr_accessor :merchant_name
after_create :create_merchant
def create_merchant
build_merchant(name: merchant_name)
save
end
create_association hasn't supported in rails 4
Also don't forget to permit merchant_name. According to this info:
class Account::RegistrationsController < Devise::RegistrationsController
before_action :configure_permitted_parameters
protected
def after_sign_up_path_for(resource)
account_users_path
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :merchant_name
end
end

Acts_as_commentable_with_threading - comments are not adding

#post.comments.all is clear. and i dont see any errors after i send form. When i click "Submit" i sent to posts/id/comments, but
my routes.rb
resources :posts do
resources :comments
end
post controller
def show
#current_user ||= User.find(session[:user_id]) if session[:user_id]
#commenter = #current_user
#post = Post.find(params[:id])
#comment = Comment.build_from( #post, #commenter.id, "234234" )
#comments = Comment.all
respond_to do |format|
format.html
format.json { render json: #post }
end
end
comments controller
class CommentsController < ApplicationController
def index
#comments = #post.comments.all
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new params[:comment]
if #comment.save
redirect_to #post # comment not save, so i dont redirect to this page
else
# is that there
end
end
end
post model
acts_as_commentable
has_many :comments
comment model
class Comment < ActiveRecord::Base
acts_as_nested_set :scope => [:commentable_id, :commentable_type]
attr_accessible :commentable, :body, :user_id
validates :body, :presence => true
validates :user, :presence => true
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_votable
belongs_to :commentable, :polymorphic => true
# NOTE: Comments belong to a user
belongs_to :user
# Helper class method that allows you to build a comment
# by passing a commentable object, a user_id, and comment text
# example in readme
def self.build_from(obj, user_id, comment)
new \
:commentable => obj,
:body => comment,
:user_id => user_id
end
#helper method to check if a comment has children
def has_children?
self.children.any?
end
# Helper class method to lookup all comments assigned
# to all commentable types for a given user.
scope :find_comments_by_user, lambda { |user|
where(:user_id => user.id).order('created_at DESC')
}
# Helper class method to look up all comments for
# commentable class name and commentable id.
scope :find_comments_for_commentable, lambda { |commentable_str, commentable_id|
where(:commentable_type => commentable_str.to_s, :commentable_id => commentable_id).order('created_at DESC')
}
# Helper class method to look up a commentable object
# given the commentable class name and id
def self.find_commentable(commentable_str, commentable_id)
commentable_str.constantize.find(commentable_id)
end
end
post view
%h2 Add a comment:
- #comments.each do |c|
= #c.body
= form_for([#post, #comment]) do |f|
.field
= f.label :body
%br/
= f.text_area :body
.actions
= f.submit
Thanks in advance and sorry for bad english
First of all you can debug why #comment.save return false yourself - just add p #comment.errors in else block and check server log.
It seems for me that you try to save invalid comments because you don't have setup user for #comment in action CommentsController#create. Comment validates presence of user!
There are several ways how to fix it. Analyzing your code I think the simplest way for you is modify CommentsController#create
#CommentsController
def create
#current_user ||= User.find(session[:user_id]) if session[:user_id]
#post = Post.find(params[:post_id])
#comment = #post.comments.new params[:comment]
#comment.user = #current_user
if #comment.save
redirect_to #post # comment not save, so i dont redirect to this page
else
# is that there
end
end
Another way is to use some gem for authentication - I recommend devise
One more way (very bad way) is to pass user_id through hidden field (you have defined #current_user in PostsController#show and user_id in attr_accessible list in Comment). But this is easy way to hack your application and write comments on behalf of any user in system!

Resources