Upon submitting sign up form, ActiveModel::ForbiddenAttributesError - ruby-on-rails

I've created a sign up form on rails, and upon clicking my submit button to save my user details, I get the following error:
ActiveModel::ForbiddenAttributesError
for this line: #user = User.new(params[:user])in my users controller.
See code below:
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "You signed up successfully"
flash[:color]= "valid"
else
flash[:notice] = "Form is invalid"
flash[:color]= "invalid"
end
render "new"
end
end
new.html.erb
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
</br> <%= f.text_field :firstname, placeholder: 'First Name' %>
</br> <%= f.text_field :lastname, placeholder: 'Last Name' %>
</br> <%= f.text_field :email, placeholder: 'Email' %>
</br> <%= f.password_field :password, placeholder: 'Password' %>
</br> <%= f.password_field :password_confirmation, placeholder: 'Confirm Password' %>
<%= f.submit :Register %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
routes.rb
Rails.application.routes.draw do
get 'users/new'
get 'pages/home'
get 'pages/howitworks'
get 'pages/about'
get 'pages/contact'
get 'pages/becomeauser'
get 'signup' => 'users#new'
resources :users

The params[:user] hash might have attributes in it that isn't a part of the User model. In your case, i'm guessing its password_confirmation.
Use strong params the next time - here
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:notice] = "You signed up successfully"
flash[:color]= "valid"
else
flash[:notice] = "Form is invalid"
flash[:color]= "invalid"
end
render "new"
end
end
private:
def user_params
params.require(:user).permit(:first_name, :last_name, :email, : password)
end

This means that you have Strong Parameters enabled. I would encourage you to read at least a part of this Rails Guide. Essentially, instead of using params[] to update or create records, you should use an intermediate method to ensure that users aren't sneaking information into your requests. This is much safer. For instance, someone could submit a "created_at" attribute with your form, and then be modifying fields which are not supposed to be edited. Your approach should instead be as follows:
Create a private user_params method in the controller which permits specified attributes
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
Replace your User.create(), User.new(), and User.update() references to params[:user] with user_params
# Do this instead of #user = User.new(params[:user])
#user = User.new(user_params)

Related

Railscasts: authentication from scratch - missing :session param issue in Rails 4

I'm working through Railscast: authentication from scratch in Rails 4, though the tutorial was built for Rails 3.
For this reason, some changes have had to be made from the original tutorial instructions.
Tutorial: http://railscasts.com/episodes/250-authentication-from-scratch?autoplay=true
Current running into an error
param is missing or the value is empty: session
Thoughts:
I've compared the 2 controllers below. My change from the tutorial is moving the params into a session_params method.
I understand the error is because the hash being posted does not contain a hash like "session" => { }. But I don't have a deep enough understanding of Rails to solve.
Recommended controller (rails 3)
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
My controller (converted to Rails 4)
def create
user = User.authenticate(session_params)
if user
session[:user_id] = user.id
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
private
def session_params
params.require(:session).permit(:email, :password)
end
Up to this point I've only been using Devise for authentication, so a great thanks in advance if you can share any advice.
UPDATE
As requested, form to post session
<h1>Log in</h1>
<%= form_tag sessions_path do %>
<p>
<%= label_tag :email %> <br/>
<%= text_field_tag :email, params[:email] %>
</p>
<p>
<%= label_tag :password %> <br/>
<%= password_field_tag :password %>
</p>
<p class="button"> <%= submit_tag %> </p>
<% end %>
UPDATE 2
Also adding user.rb model
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, password_salt)
user
end
end
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
Try this one:
in sessions_controller.rb
def create
#user = User.find_by(email: params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
flash[:success] = "#{#user.email}, Successfully Logged In"
redirect_to root_url, :notice => "Logged in!"
else
flash.now[:danger] = "Incorrect User/Password"
render 'new'
end
end
html form
<%= form_for :session, url: :sessions do |f| %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<%= f.submit "Sign In", class: "button" %>
<% end %>
routes.rb
post 'sessions' => 'sessions#create'
User.rb
class User < ActiveRecord::Base
has_secure_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
end

Can't log in to my database. Error: "Param is missing or the value is empty: user"

I'm having a trouble with my logging in. It highlights the user_params function as an error in users controller. What could it be?
/views/sessions/new.html.erb or login form
<h1>Log In</h1>
<%= form_tag users_path do %>
<div class="field">
<%= label_tag :email %><br />
<%= text_field :email, params[:email] %>
</div>
<div class="field">
<%= label_tag :password %><br />
<%= password_field_tag :password %>
</div>
<div class="actions"><%= submit_tag "Log In" %></div>
<% end %>
controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged In!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to signup_path, notice: "Logged out!"
end
end
controllers/users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to user_tasks, notice: "Thank you for signing up!"
else
render "new"
end
end
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not authorized" if current_user.nil?
end
end
rake routes
Generated parameters
{"utf8"=>"✓", "authenticity_token"=>"jtdA0rITCiFjU9ECiKnDUMh/MHMpqv6u+Bd65PAfpARwYsmb9Dli32wpULfmYa7wpBQiFYxAGHF6flCfJgPOew==", "email"=>"dsadsa", "password"=>[FILTERED]", "commit"=>"Log In"}
Any help?
change this line and try please.
<%= text_field :email, params[:email] %>
to
<%= text_field_tag :email, params[:email] %>
Also majorly add this in your routes file to redirect it to sessions controller create action.
post '/authenticate' => 'sessions#create'
change this tag
<%= form_tag users_path do %>
to
<%= form_tag /authenticate do %>
When you look into the params, they are not coming from the user. Try changing your user_params like below
def user_params
params.permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
I suggest you keep the :user namespace for params in your form
<%= form_tag users_path do |form| %>
<%= fields_for :user do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email, params[:email] %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="actions"><%= submit_tag "Log In" %></div>
<% end %>
<% end %>
So you can still use params.require(:user) in your controller as usual
Parameters will look like this
{
"utf8"=>"✓",
"authenticity_token"=>"jtdA0rITCiFjU9ECiKnDUMh/MHMpqv6u+Bd65PAfpARwYsmb9Dli32wpULfmYa7wpBQiFYxAGHF6flCfJgPOew==",
"user" => {
"email"=>"dsadsa",
"password"=>[FILTERED],
},
"commit"=>"Log In"
}

Rails 4 + Devise Separate User CRUD

I'm using Rails 4 to build a simple Admin interface for adding and removing users, or CRUD.
I'm currently having Devise installed and have built the basic views and actions.
However after filling out the forms myself, this is what I get:
2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
This is what I have currently: (removed registerable since I don't want to have a public registration)
Models > user.rb
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
end
views > users > new.html.erb
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #validatable %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Create User" %>
</div>
<% end %>
routes.rb (currently I make new user through "/admin/users/new" )
Rails.application.routes.draw do
devise_for :users
scope '/admin' do
resources :users
end
end
Controllers > users_controller.rb
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[user_params])
if #user.save
redirect_to #user, :flash => { :success => 'User was successfully created.' }
else
render :action => 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[user_params])
sign_in(#user, :bypass => true) if #user == current_user
redirect_to #user, :flash => { :success => 'User was successfully updated.' }
else
render :action => 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_path, :flash => { :success => 'User was successfully deleted.' }
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Does anyone have any thoughts as to what is causing the error?
Thanks :D
Just a note: previously, before I disabled :registerable in devise_modules in user.rb, I can actually perform sign-ups using the default devise view "users/sign_up". However what I want is still to get an admin CRUD system, so I disabled it anyway.
Is it typo in your def create/update:
#user = User.new(params[user_params])
# should be
#user = User.new(user_params)
if #user.update_attributes(params[user_params])
# should be
if #user.update_attributes(user_params)

The action 'create' could not be found for Admin::UsersController

I am stuck with this issue, and i am not able to identify the problem. I am trying to add a user from admin section. Hence I have created a custom user controller, which calls the devise model. And I am trying to insert and update values using custom forms.
Controller
class Admin::UsersController < ApplicationController
load_and_authorize_resource
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :authenticate_user!
layout 'admin-layout'
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit({ roles: [] }, :email, :password, :password_confirmation) }
end
def index
#user = User.all
end
def new
#user = User.new
end
def create
#user = User.new
if #user.save
redirect_to :action => "index"
else
render :action => "new"
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes
redirect_to :action => "index"
else
render :Action => "update"
end
end
def destroy
User.find(params[:id]).destroy
redirect_to ::Action => "index"
end
end
View File
<div class="container">
<div class="col-md-6 col-md-offset-2">
<h2>Create New User</h2>
<%= form_for #user, url: {action: "create"} do |f| %>
<%= f.text_field :email, :class=>"form-control", :placeholder => "Enter Email", :required => "true" %>
<%= f.text_field :password, :class=>"form-control", :placeholder => "Enter Password", :required => "true" %>
<%= f.text_field :password_confirmation, :class=>"form-control", :placeholder => "Enter Password Again", :required => "true" %>
<p>Roles:</p>
<% for r in Role.all %>
<%= check_box_tag "user[role_ids][]", r.id %>
<%= r.name %>
<% end %><br/>
<%= f.submit "Create", :class=>"btn btn-primary" %>
<% end %>
</div>
<div>
Routes
admin_users GET /admin/users(.:format) admin/users#index
POST /admin/users(.:format) admin/users#create
Can any1 please point me out where am I making a mistake.
You defined new, create etc. methods as protected, they need to be public if you want them to be recognized as actions.
BTW, in Ruby, if you have collection Role.all, it's much more readable to iterate over this with each instead of for (which is rarely used here):
<% Role.all.each do |r| %>

Can't mass-assign protected attributes with ruby-on-rails

I am trying to have a nested form on my users/new page, where it accepts user-attributes and also company-attributes. When you submit the form:
Here's what my error message reads:
ActiveModel::MassAssignmentSecurity::Error in UsersController#create
Can't mass-assign protected attributes: companies
app/controllers/users_controller.rb:12:in `create'
Here's the code for my form:
<%= form_for #user do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.fields_for :companies do |c| %>
<%= c.label :name, "Company Name"%>
<%= c.text_field :name %>
<% end %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
<br>
<% if current_page?(signup_path) %>
<%= f.submit "Sign Up", class: "btn btn-large btn-primary" %> Or, <%= link_to "Login", login_path %>
<% else %>
<%= f.submit "Update User", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
Users Controller:
class UsersController < ApplicationController
def index
#user = User.all
end
def new
#user = User.new
end
def create
#user = User.create(params[:user])
if #user.save
session[:user_id] = #user.id #once user account has been created, a session is not automatically created. This fixes that by setting their session id. This could be put into Controller action to clean up duplication.
flash[:success] = "Your account has been created!"
redirect_to tasks_path
else
render 'new'
end
end
def show
#user = User.find(params[:id])
#tasks = #user.tasks
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = #user.name.possessive + " profile has been updated"
redirect_to #user
else
render 'edit'
end
#if #task.update_attributes params[:task]
#redirect_to users_path
#flash[:success] = "User was successfully updated."
#end
end
def destroy
#user = User.find(params[:id])
unless current_user == #user
#user.destroy
flash[:success] = "The User has been deleted."
end
redirect_to users_path
flash[:error] = "Error. You can't delete yourself!"
end
end
Company Controller
class CompaniesController < ApplicationController
def index
#companies = Company.all
end
def new
#company = Company.new
end
def edit
#company = Company.find(params[:id])
end
def create
#company = Company.create(params[:company])
#if #company.save
#session[:user_id] = #user.id #once user account has been created, a session is not automatically created. This fixes that by setting their session id. This could be put into Controller action to clean up duplication.
#flash[:success] = "Your account has been created!"
#redirect_to tasks_path
#else
#render 'new'
#end
end
def show
#comnpany = Company.find(params[:id])
end
end
User model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :name, :email, :password, :password_confirmation
has_many :tasks, dependent: :destroy
belongs_to :company
accepts_nested_attributes_for :company
validates :name, presence: true, length: { maximum: 50 }
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, length: { minimum: 6 }
#below not needed anymore, due to has_secure_password
#validates :password_confirmation, presence: true
end
Company Model
class Company < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :users
end
First for debugging put the bang on the create in the two controllers like so: create! Your log may spit out more.
Then, if that sucked, try it the old fashioned way of Building the two Objects and assigning each one with the params.
I assume also that this is it for attributes, no after saves that should have more to the schema then you are showing.
Lastly, you are missing
def new
#user = User.new
#company = #user.companies.build
end
Print out the params too, just in case it says something wonky but adding this line: as #Beerlington said should work too :company_attributes, maybe companies_attributes... spit balling here.
Add attr_accessible :companies to your user model attr list

Resources