Undefined method attr_accessible error for User - ruby-on-rails

I'm trying to create a login of sorts. I created a User scaffold and have this code in my user.rb
class User < ActiveRecord::Base
attr_accessible :name, :password_digest, :password, :password_confirmation
has_secure_password
end
I keep getting this error
undefined method `attr_accessible' for #<Class:0x396bc28>
Extracted source (around line #2):
1
2
3
4
5
class User < ActiveRecord::Base
attr_accessible :name, :password_digest, :password, :password_confirmation
has_secure_password
end
Rails.root: C:/Sites/web

attr_accessible is not available for Rails version 4+. You would have to go with strong parameters.
With Strong Parameters, attribute whitelisting has been moved to controller level. Remove the attr_accessible call from your model.
Here is an example in Rails Guide of how to use Strong Parameters
In your case you can do something like this:
class UsersController < ApplicationController
## ...
def create
#user = User.new(user_params) ## Invoke user_params method
if #user.save
redirect_to #user, notice: 'User was successfully created.'
else
render action: 'new'
end
end
## ...
private
## Strong Parameters
def user_params
params.require(:user).permit(:name, :password_digest, :password, :password_confirmation)
end
end
You can take a note of #Frederick comment below my answer,
you can still use attr_accessible but it has been extracted into the
protected_attributes gem (although clearly strong parameters is the
way forwards)

Related

Rails - How to add additional column value into Devise registration table?

User Model
class User < ApplicationRecord
belongs_to :tenant, dependent: :destroy
end
Tenant Model
class Tenant < ApplicationRecord
has_many :users
end
Controller
Workaround 1 (not working)
def create
super
#tenant = Tenant.new
#user = #tenant.build_user(params)
#tenant.save
end
Workaround 2 (not working)
def create
#tenant = Tenant.new
#user = User.build(params)
#tenant.save
super
end
Is there any possibilities to pass a parameter to devise super class?
Since Devise super method has its own functionality on user registration/password hashing/, I can not completely override the function.
I know the way I am saving is wrong, please suggest me the better approach.
Actual source code:
(with Controller, Model, Migrations and Routes files are added.)
https://repl.it/#aravin/HarmlessRepentantHarddrive
You can override the sign_up_params in your controller:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation...).merge({tenant_id: Tenant.create!.id})
end
end
I wanted to provide a little more verbose answer than was provided by AbM.
You can generate the registrations_controller.rb file with the following command:
rails g devise:controllers users -c=registrations
Once you do this, you will want to modify it such that you have something like:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
Then in your routes.rb file you will want to change the devise_for line to tell devise that you want to override your registrations controller like:
devise_for :users, controllers: { registrations: 'users/registrations' }
Of course, you will want to replace the :user/:users references to the name of your devise authentication model if you are using something other than the standard User throughout my example.
Here is a reference to this in the official docs on GitHub.

One Model and two controller validation Ruby on Rails?

One thing that confuses me the most is when doing validation in one model with two controllers. I have a login system which register and logs users in. There both use the same model but both does not use the same amount of HTML widgets. One controller contains password, retype password, user name, first & second name and so on. The second controller uses only the user name and password fields. How would you do validation in the same model for this situation?
Thank you
here is the controller that register new users:
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 '/cool'
else
#user = Newuser.new
#user.valid?
#user.errors.messages
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :salt, :firstname, :secondname, :address, :postcode)
end
end
second controller:
class LoginsController < ApplicationController
before_filter :authorize
def index
#rentals = Rental.where(user_id: current_user.id).limit(5)
#buys = Buy.where(user_id: current_user.id).limit(5)
#users = User.where(id: current_user.id)
#buyGames = BuyGame.where(user_id: current_user.id).limit(5)
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to '/logout'
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(account_params)
redirect_to '/cool'
else
render 'edit'
end
end
private
def account_params
params.require(:user).permit(:name, :email, :password, :salt, :firstname, :secondname, :address, :postcode)
end
end
Here is my model:
class User < ApplicationRecord
has_secure_password
end
One way to go is to remove validations from the model and put them in form objects. For this case, you'll have two form objects, each with its own set of validations. And you use the appropriate one in respective controllers. Something along these lines:
# logins_controller
def update
login_form = FormObjects::LoginForm.new(login_params)
if login_form.valid?
redirect_to '/cool'
else
render 'edit'
end
end
# users controller
def create
signup_form = FormObjects::SignupForm.new(user_params)
if signup_form.save
redirect_to '/cool'
else
render 'new'
end
end
# signup_form
module FormObjects
class SignupForm
include ::ActiveMode::Model
validate_presense_of :email, :password, :password_confirmation, :address, :whatever_else
def save
# create user here
end
end
end
# login_form
module FormObjects
class LoginForm
include ::ActiveMode::Model
validate_presense_of :email, :password
end
end
You can simply specify validations on actions, that is:
validates :first_name, presence: true, on: :create # which won't validate presence of first name on update or any other action
I believe the trick you are looking for is to define validation actions on create/update of the model. Something roughly along these lines:
class User < ActiveRecord::Base
# These are example validations only; replace with your actual rules.
validates :password, confirmation: true
validates_presence_of :username
validates :first_name, presence: true, format: {with: /.../}, on: create
validates :last_name, presence: true, format: {with: /.../}, on: create
end
...However, I am unclear why you would want to do this in your specific example. It would be advisable to always run all validation checks on fields like first_name, to help maintain data integrity.

Rails ActiveModel::ForbiddenAttributesError - ActiveModel::ForbiddenAttributesError в simple_form nested_fields

I experience a trouble while saving simple_form.fields_for - forbidden attributes error
'create' action in bookings controller looks so:
def create
...
new_params = params[:booking]
new_params[:user_attributes] = new_params[:user_attributes].merge({"password"=>"osmsmsmsm32"}) # password is temp stuff to bypass User save validation
#booking = Booking.new
#booking.update(params)
# however #booking.user.update(params[:booking][:user_attributes]) gives the same error
...
end
...
def booking_params
params.require(:booking).permit(:arrived_at, :departured_at, :arrival_address,
:departure_address, :arrival_city, :departure_city,
:reservation_cost, :total_additional_cost, :user_attributes, :user_id, :garage_id,
user_attributes: [:id, :name, :surname, :email, :phone],
garage_attributes: [:id]
)
end
===========================
Booking:
belongs_to :user
accepts_nested_attributes_for :user
===========================
##In model User:
has_many :bookings
However #booking.user.save & #booking.save in irb console with same params are successfully saveable and true is passed, without any Forbidden Attribute error.
Where is this Forbidden attribute come from? I am sure I allowed all the attrs I send in the form, and I think I use accepts_nested_attributes_for properly, isn't it?
Just Define your user_attributes inside controller private method as per below:
private
def user_params
params.require(
:user
).permit(
:first_name,
:last_name,
:job_title
)
end
if you are working with nested filed just add nested attributes inside this attributes like below:
private
def user_params
params.require(
:user
).permit(
:first_name,
:last_name,
:job_title,
addresses_attributes: [:address_1, :address_2]
)
end
write nested attributes by take in mind your model associations,
Hope this will work for you. :)

Rails password can't be blank error

I am trying to create a user signup form in Rails 4.1.6. I keep getting a 'password can't be blank' error. I can see that both the password and password_confirmation are in the params hash but not in the params[:user] sub-hash. I cannot figure out why for the life of me. Any help will be greatly appreciated.
User Model:
class User < ActiveRecord::Base
belongs_to :company
has_secure_password
end
Users Controller:
class UsersController < ApplicationController
respond_to :json
def index
#users = User.all
respond_with(#users)
end
def create
#user = User.new(user_params)
#user.save
respond_with(#user)
end
private
def user_params
params.require(:user).permit(:given_name, :family_name, :email, :password, :password_confirmation)
end
end
It sounds like your parameters are not being sent to the server correctly.
password should be sent as user[password] and password_confirmation should be sent as user[password_confirmation].
See documentation for hash and array parameters.
Alternatively, adding wrap_parameters to the controller will wrap parameters into a nested hash.
wrap_parameters :user, include: [:given_name, :family_name, :email, :password, :password_confirmation]
See documentation for ActionController::ParamsWrapper.

Unknown attribute rails 4

im new into Rails 4 development and rails in general. I red official "getting started with rails" guide where it is shown how to create blog. So I want to do my own from 0 registration, auth system.
While creating new user I get this error. I do not understand what I am doing wrong. Any advice?
Git repo:
https://github.com/pumpurs/auth
ActiveRecord::UnknownAttributeError in UsersController#create
unknown attribute: password
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user].permit(:password, :email, :password_confirmation))
end
private
def user_params
params.require(:user).permit(:password, :email, :password_confirmation)
end
end
Model file:
class User < ActiveRecord::Base
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def enrypt_password
if password.present?
self.password_salt = BCript::Engine.generate_salt
self.password_hash = BCript::Engine.generate.hash_seret(password, password_salt)
end
end
end
You need to add attr_accessor :password to your User model, to provide a non-db-backed attribute to use to base your db-backed password_hash attribute off of.

Resources