I am trying to update the profile of a user, however, I am getting an ArgumentError (wrong number of arguments (given 6, expected 1)): The relation between the user model and user profile model is one-to-one
application_controllers.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user, :logged_in?
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
def create
#user_profile = UserProfile.new(user_profile_params)
#user_profile.user_id = current_user.id
if #user_profile.save
format.html {redirect_to home_index_path, notice:"Account created successfully" }
else
flash.now.alert = "Oops, couldn't create account. Please make sure you are using a valid email and password and try again."
format.html { render :new }
end
end
private
def user_profile_params
params.require(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
Problem is on this line:
def user_profile_params
params.require(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
You should use either:
def user_profile_params
params.require(:user_profile).permit(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
or
def user_profile_params
params.permit(:first_name, :other_name, :last_name, :phonemumber, :email, :seller_id)
end
Depends on data you are getting from the form. And btw. there is a typo in :phonemumber should probably be :phonenumber.
Related
I do not want to allow the user to update their :name. I found this question for Rails version 3 but the answer does not work for me. I am using Rails 4. I might just have the wrong syntax. I couldn't get #user.update_attributes(params[:user]) to work. Only: #user.update_attributes(user_params). I am not including :name on my edit form, but my understanding (??) is that a user could still pass it through the browser themselves and with my current code they could change :name.
class UsersController < ApplicationController
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.update_attributes(user_params)
if #user.save
flash[:success] = "Profile updated"
redirect_to #user
else
flash[:danger] = "Profile update Unsuccessful"
redirect_to 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :email_confirmation, :password, :password_confirmation)
end
There's more than one way to assure users won't tamper with your business rules.
As you're already using Rails 4, you can take advantage of strong parameters to deny access to the :name attribute.
You can have different sets of rules for each controller action:
def create_user_params
params.require(:user).permit(:name,:email, :email_confirmation, :password, :password_confirmation)
end
def update_user_params
params.require(:user).permit(:email, :email_confirmation, :password, :password_confirmation)
end
#user.create(create_user_params)
#user.update_attributes(update_user_params)
drying up:
def allowed_update_attrs
[:email, :email_confirmation, :password, :password_confirmation]
end
def allowed_create_attrs
allowed_update_attrs + [:name]
end
def user_params
params.require(:user)
end
#user.create user_params.permit(*allowed_create_attrs)
#user.update_attributes user_params.permit(*allowed_update_attrs)
There are other ways of accomplishing the same thing like tapping into already permitted attributes, but this way seemed simpler.
users_controller.rb
class UsersController < ApplicationController
include UsersHelper
def new
#user = User.new
end
def create
if isUsernameTaken?
render 'new'
elsif isEmailTaken?
render 'new'
else
#user = User.new(user_params)
if #user.save
else
render 'new'
end
end
end
private
def user_params
params.require(:user).permit(:username,:email,:password,:password_confirmation)
end
end
users_helper.rb
module UsersHelper
def isUsernameTaken?
!(User.find_by(username: params[:username]).nil?)
end
def isEmailTaken?
!(User.find_by(email: params[:email]).nil?)
end
end
The problem is isUsernameTaken? or isEmailTaken? never gets executed and always the else part gets executed even if I give same username again. Why is this happening?
This is because params[:username] and params[:email] are always blank in your controller. They should be params[:user][:username] or user_params[:username].
Anyway, those kind of checks belongs to the model, not the controller and there already are validators to do exactly what you want:
class User < ActiveRecord::Base
validates :email, :username, uniqueness: true
end
I am getting an error when I pass in my url to reset my password for example: localhost:3000/password_reset/SADASIJDSIDJ1231231/edit <---- gives me ActiveRecord::RecordNotFound and its pointing at in my password_reset_controller
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
This is my application controller (notice the "include SessionsHelper")
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
#om du lägger till kod här kmr inte sessions funka när du är inloggad wtf???
#tog bort detta protect_from_forgery with: :exception
include SessionsHelper
protect_from_forgery
private
def current_user
#current_user ||= User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end
helper_method :current_user
end
This is my password_reset_controller
class PasswordResetsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "Email sent with password reset instructions."
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password reset has expired."
elsif #user.update_attributes(params.permit![:user])
redirect_to root_url, :notice => "Password has been reset!"
else
render :edit
end
end
end
HOW I SOLVED IT:
So thanks to jorge I knew password_reset_token wasn't generated in the database. So I went back to my model/user.rb
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
I added back "save!" it was "save" before. Then I got another error saying password can't be blank.
So I deleted these two lines
# validates :password, length: { minimum: 6 }, presence: true
#validates :password_confirmation, presence: true
Instead I added this line
validates_presence_of :password, :on => :create
Now everything works. Thanks for your patience jorge. I owe u one big.
Did you check in the database that the a user exists with password reset token "SADASIJDSIDJ1231231"?
Looks like following line is not finding a user:
#user = User.find_by_password_reset_token!(params[:id])
Please include your User class - the send_password_reset method may not be saving the token correctly.
I current use Rails 4 and I move the app from attr_accessible to the StrongParams. So, I have customised Devise controller:
class UsersController < Devise::RegistrationsController
load_and_authorize_resource
#...
def update
unless #user.userable?
if params[:selected_person_type] == I18n::t('activerecord.attributes.user.individual')
redirect_to new_individual_path and return
elsif params[:selected_person_type] == I18n::t('activerecord.attributes.user.legal_entity')
redirect_to new_legal_entity_path and return
end
end
#avatar = params[:avatar_id].present? ? Avatar.find_by(id: params[:avatar_id]) : #user.avatar
if params[:user][:password].blank?
if #user.update_without_password(user_params)
notice = if #user.unconfirmed_email.present? && Date.today == #user.confirmation_sent_at.to_date
t('devise.confirmations.send_instructions')
else
t('views.messages.notices.personal_data_updated')
end
redirect_to edit_user_path(#user), notice: notice and return
end
else
if #user.valid_password?(params[:user][:current_password])
params[:user].delete("current_password")
if #user.update_attributes(user_params) && #user.save
sign_in(#user, bypass: true)
redirect_to edit_user_path(#user), notice: t('views.messages.notices.personal_data_updated') and return
end
else
#user.errors.add(:current_password, :invalid)
end
end
render action: "edit"
end
def create
if resource.save
SystemMailer.send_mail(to: resource.email, body: resource.temp_password, subject: I18n.t('mailers.password.new')).deliver if resource.generate_password == '1'
if request.xhr?
expire_data_after_sign_in!
respond_to do |format|
format.js
end
else
super
end
else
if request.xhr?
clean_up_passwords(resource)
respond_to do |format|
format.js
end
else
super
end
end
end
private
def user_params
if current_user.present?
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
end
end
I got the error before:
Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
ActiveModel::ForbiddenAttributesError:
ActiveModel::ForbiddenAttributesError
This is because CanCan isn't so compatible with StrongParams, so i tried this fix in ApplicationController:
class ApplicationController < ActionController::Base
include SimpleCaptcha::ControllerHelpers
include CaptchaHelper
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :cancan_workaround
rescue_from CanCan::AccessDenied do |e|
redirect_to '/', flash: { error: I18n.t('views.messages.notices.access_denied') }
end
private
def cancan_workaround
resource = controller_name.singularize.to_sym
method = "#{resource}_params"
params[resource] &&= send(method) if respond_to?(method, true)
end
end
After that fix i got that error:
UsersController should successfully create user
Failure/Error: post :create, user: attributes_for(:unconfirmed_user)
NoMethodError:
undefined method `permit' for nil:NilClass
# ./app/controllers/users_controller.rb:75:in 'create'
# ./spec/controllers/users_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:9:in `block (2 levels) in <top (required)>'
Here is ./app/controllers/users_controller.rb:75:in 'create' is super call in the action. Any idea how to fix that?
Devise
Devise doesn't work like other Rails input systems - it uses its own backend functionality to process the params. It seems devise automatically permits the email & password params, and its your job to add the other params its parameter_sanitizer
Devise and Strong Parameters
Bottom line is that, according to the Devise documentation, you'll have to use something like this:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Ok, i got it. Problem was not in Devise, it was with my permissions:
private
def user_params
if current_user.present?
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
end
Test evaluated for non-signed user, so when cancan's hook tried to execute this method:
params[resource] &&= send(method) if respond_to?(method, true)
It received nil, because user wasn't signed-in, so hook transformed :user => { ... } into the :user => nil. So, i fixed it via removing current_user.present?.
private
def user_params
params.require(:user).permit(:fullname, :about, :username, :email, :current_password, :password, :password_confirmation)
end
Not sure how well this solution is secure.
What I am trying to do is to go to user's page after signin/up. On the error page is written that the error is in users_controller. So this is my user controller:
class UsersController < ApplicationController
def show
#user = User.find([:id])
end
def index
end
def new
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
# Handle a successful save.
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
Your show method should be:
def show
#user = User.find( params[:id] )
end
And not [:id] alone. You're accessing the :id key at the params hash object.