ActiveAdmin does not save attributes not coming from params - ruby-on-rails

While creating an active admin record, am trying to save an attribute (role_type) which does not come from params.
However, the attribute does not get saved in creation.
I have added it to permit_params.
permit_params :email, :password, :password_confirmation, :phone_no, :name, :role_type, role_ids: []
controller do
def create
user = User.create(name: params[:user][:name], email: params[:user][:email], password: SecureRandom.hex, role_type: "employee")
flash[:notice] = "User Created"
redirect_to admin_user_path(user)
end
end

If you want to combine a params hash with some attributes that you assign manually the cleanest way is by using a block
permit_params :email, :password, :password_confirmation, :phone_no, :name, :role_type, role_ids: []
controller do
def create
user = User.create(permitted_params[:user]) do |u|
u.password = SecureRandom.hex
end
flash[:notice] = "User Created"
redirect_to admin_user_path(user)
end
end
However your password encryption scheme is very naive - I would recommend you use ActiveModel::SecurePassword instead of trying to reinvent the password encryption wheel and creating a insecure authentication system.
Another major issue is that you are not actually checking if the user is created!
permit_params :email, :password, :password_confirmation, :phone_no, :name, :role_type, role_ids: []
controller do
def create
user = User.new(permitted_params[:user]) do |u|
u.password = SecureRandom.hex
end
if user.save
flash[:notice] = "User Created"
redirect_to admin_user_path(user)
else
render :new
end
end
end

Related

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.

how validation is done using wicked?

I have a users_controller and a user_steps_controller which has three steps :business, :payment and :login
In the user.rb model
class User < ActiveRecord::Base
validates_presence_of :fname, :lname, :email, :mob, :country, :state, :suburb, :postal ,:add
end
while checking validation if i put some random values then also it is giving errors
Fname can't be blank
Lname can't be blank
Email can't be blank
Mob can't be blank
Country can't be blank
State can't be blank
Suburb can't be blank
Postal can't be blank
Add can't be blank
Please help me out
This is my users_controller
def new
#user = User.new
end
def create
#user = User.new(params[:id])
if #user.save
session[:user_id]= #user.id
#user.update_attributes(user_params )
redirect_to user_steps_path
else
render :new
end
end
private
def user_params
params.require(:user).permit( :fname, :lname, :email, :mob, :gender_male, :gender_female, :country, :state, :suburb, :postal ,:add, :cmpyname, :abnacn, :cmpyadd, :cmpydet,:cash, :paypal,:bsb,:usrname,:password_hash, :password_salt, :selcat, :protit, :prodes)
end
user.rb
class User < ActiveRecord::Base
validates :fname, :lname, :email, :mob, :country, :state, :suburb, :postal ,:add, :presence => true
attr_accessor :current_step
validates_presence_of :cmpyname, :abnacn, :cmpyadd, :cmpydet, if: -> { current_step?(:business) }
validates_presence_of :usrname,:password_hash, :password_salt, :selcat, :protit, :prodes, if: -> { current_step?(:login) }
def current_step?(step_key)
current_step == step_key
end
end
user_steps_controller
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :business, :login, :payment
def show
#user = current_user
render_wizard
end
def update
#user = current_user
params[:user][:current_step] = step
#user.update_attributes(user_params )
render_wizard #user
end
private
def user_params
params.require(:user).permit( :cmpyname, :abnacn, :cmpyadd, :cmpydet,:cash, :paypal,:bsb,:usrname,:password_hash, :password_salt, :selcat, :protit, :prodes)
end
end
user.rb
def current_step?(step_key)
current_step == step_key
end
user_steps_controller.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :personal, :social
def show
#user = current_user
render_wizard
end
def update
#user = current_user
params[:user][:current_step] = step
#user.attributes = user_params
render_wizard #user
end
private
def redirect_to_finish_wizard(options = nil)
redirect_to root_url, notice: "Thank you for signing up."
end
def user_params
params.require(:user).permit(:name, :current_step, :date_of_birth, :bio, :twitter_username, :github_username, :website)
end
end
This method will work for you.
Your real problem is here:
#user = User.new(params[:id])
I'm assuming params[:id] is nil, because otherwise that would fail. Basically, your instantiating a User with no data supplied and trying to save it. So clearly those validations you have supplied will fail. If you're actually submitting a form with user data you need to pass user_params you've already defined as follows:
#user = User.new(user_params)
If you need to have validations occur on your User model in different steps, you'll need to have the validations run conditionally dependent on the state of the form:
class User
attr_accessor :current_step
validates_presence_of :business_related_attr, if: -> { current_step?(:business) }
def current_step?(step_key)
current_step.blank? || current_step == step_key
end
end

forgot password using devise rails

I am using devise for user in my rails application
When i click on forgot password than it send mail to user for reset password instruction.
but when i click on that password reset link in mail it redirect to my custom user controller which i create for user edit profile...
how to call devise password edit method
below is my controller/users.
class UsersController < ApplicationController
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:notice] = "Profile successfully updated"
redirect_to authenticated_root_path
else
render 'edit'
end
end
def change_password
#user = User.find(current_user.id)
end
private
def user_params
params.require(:user).permit(:email, :first_name, :last_name,
:dob, :address, :zip_code, :about_me, :country_id, :state_id,
:city_id, :phone_no, :status, :profile_pic, :gender,
:password, :password_confirmation)
end
end
Use this path for password reset for devise:
edit_user_registration_path

Allow users to edit their account without providing a password | Rails4

In Rails 3 it worked just fine, but with my new Rails4 Appp i don't know whats the problem.
The Guide on the Devise GitHub Page
My Registrations Controller
def update
# required for settings form to submit when password is left blank
if params[:user][:password].blank?
params[:user].delete("password")
params[:user].delete("password_confirmation")
end
#user = User.find(current_user.id)
if #user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
My Application Controller
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:name, :first_name, :user_name, :email, :password, :password_confirmation, :provider, :uid)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:name, :email, :password, :password_confirmation, :first_name, :last_name,
:user_name, :avatar, :profile_cover, :facebook_link,
:twitter_link, :instagram_link, :status)
end
end
I added the controller to my Routes
:registrations => "registrations"
And i Changed the update calls using the appropriate method below:
#user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
But i'm getting a NoMethodError in RegistrationsController#update Error.
I don't know yet if this is a good practice but i changed in my RegistrationsController the update action to
#user.update_attributes(account_update_params)

Rails Scaffold destroy not working as expected

I was adding uniqueness validation to the model in charge of user registration. The username should be uniqueness.
I created a user when testing some days ago, lets call it "example-guy". Then I deleted him from the scaffolding user interface and now when trying to register a new user as "example-guy", it returns that the name has already been taken.
So how can I fix this from the DB without reverting to its "birth-state" and modify the controller to actually destroy the table entry?
Or maybe Rails is keeping track of what was writed to DB, even after destruction?
Im using omniauth-identity, the user model:
class User < ActiveRecord::Base
attr_accessible :name, :provider, :uid, :email
# This is a class method, callable from SessionsController
# hence the "User."
def User.create_with_omniauth(auth)
user = User.new()
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["name"]
# ADD EMAIL
user.email = auth["info"]["email"]
user.save
return user
end
end
User controller's destroy function:
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
Validations are made trought "Identity" model inherited from omniauth's active record:
class Identity < OmniAuth::Identity::Models::ActiveRecord
attr_accessible :email, :name, :password_digest, :password, :password_confirmation
#attr_accessible :email, :name, :password_digest :password, :password confirmation
validates_presence_of :name
validates_uniqueness_of :name
validates_length_of :name, :in => 6..24
validates_format_of :name, :with => /^[a-z]+$/
validate :name_blacklist
validates_uniqueness_of :email, :case_sensitive => false
validates_format_of :email,
:with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
:message => "doesn't look like a proper email address"
#validates_presence_of :password, on: :create
#validates_presence_of :password_confirmation
validates_length_of :password, :in => 6..24
def name_blacklist
unless self.name.blank? then
case self.name
when "user", "photo", "photos",
"application", "sessions",
"identities", "home"
self.errors.add(:name, "prohibited")
end
end
end
end
Identities controllar manage registration form sent to omniauth and calling new.html.erb:
class IdentitiesController < ApplicationController
def new
#identity = env['omniauth.identity']
end
end
Thanks in advance.
I'm not entirely sure what caused the problem, but I came across a similar problem but with email addresses with a Devise based user.
I was wanting to re-use the same email on a different user. I changed the original user to a different email, but when I then tried to update the second user with the "now unique" email, it failed the unique validation.
A query for users with that email returned nothing.
It seemed to be cache-related to the uniqueness constraint, as restarting the server, after deleting the email address, fixed the problem.

Resources