Rails map one field in form to two fields in model - ruby-on-rails

I've seen a lot of posts about how to map 2 form fields to one model field, but what about mapping 1 form field to provide answers for two (or more) model fields? I have a form for users which gives a field, last_name, for a user. But I want the default password for that user to also be last_name (and I have password_confirmation set up, so that also needs to be last_name). How would I do this?
Form:
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
<%= f.label :last_name %>
<%= f.text_field :last_name, :password, :password_confirmation,
class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.hidden_field :access_level, :value => "Chair" %>
<%= f.label :Phone %>
<%= f.text_field :phone_number, :id => "phone", class: 'form-control' %>
<p> </p>
<div class="col-md-12">
<%= f.submit "Add Chair", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
user_controller.rb
def create
#user = User.new(user_params)
if #user.save
log_in #user
current_user
flash[:success] = "Welcome to the Penn Model Congress!"
redirect_to after_sign_in_path
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:password_confirmation, :access_level,
:phone_number)
end
end

I would add a before_validation callback to the User model like this:
# in app/models/user.rb
before_validation :set_default_password
private
def set_default_password
self.password ||= last_name
self.password_confirmation ||= last_name
end

If this will be your default and you don't want the user to be able to override it on creation, you could set it on the controller:
View:
<%= f.text_field :last_name, class: 'form-control' %>
Controller:
def create
#user = User.new(user_params)
#user.password = #user.last_name
#user.password_confirmation = #user.last_name
if #user.save
log_in #user
current_user
flash[:success] = "Welcome to the Penn Model Congress!"
redirect_to after_sign_in_path
else
render 'new'
end
end

Related

Form data not getting saved to database

I'm new to RoR and I'm trying to create a sign-up form. When I click on 'Create my account', data does not get saved to the database. I have added resources: users to my routes file. Is there something else I'm missing?
This is my view (signup.html.erb)
Sign Up
<%= form_for #user, :url => { :action => "create" } do |f| %>
<%= f.label :emp_id,"Employee ID" %><br>
<%= f.text_field :emp_id, class: 'form-control' %><br><br>
<%= f.label :password, "Password" %><br>
<%= f.password_field :password, class: 'form-control' %><br><br>
<%= f.label :password_confirmation, "Password Confirmation" %><br>
<%= f.password_field :password_confirmation, class: 'form-control' %><br><br>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
This is my controller
class UsersController < ApplicationController
def new
#user = User.new
end
def signup
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
render 'login'
else
render 'signup'
end
end
def user_params
params.require(:user).permit(:emp_id, :password)
end
end
You need to permit :password_confirmation
def user_params
params.require(:user).permit(:emp_id, :password, :password_confirmation)
end
And make sure there are no other validations like email presence or that will cause validations to fail

Rails submit form with get parameters from url

I have form for signup user and when this url have get parameter like
http://localhost:3000/signup?list_id=10
need transfer this parameters to action for create user
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages', user: #user %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit yield(:button_text), class: "btn btn-primary" %>
in this action user create dont see this parameter
def create
debugger
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
render "new"
end
end
(byebug) params<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"I5+lc0T2fqy2Ie56rMnkR6Eff60nJmiuaTob7xAqknB6YgHZpmEByyRpCanpnNqyO9H/wMWbm7IumdXRyUABcA==", "user"=>{"name"=>"Ivan", "email"=>"ss#ss.com", "password"=>"222", "password_confirmation"=>"222"}, "commit"=>"Create my account", "controller"=>"users", "action"=>"create"} permitted: false>
It's available in your params hash so you can add it to your form as a hidden field so it will be submitted with the other params. Then make sure to whitelist that parameter in your controller.
First, add the virtual attribute to your User model if :list_id isn't already a persisted attribute for Users. This is done by adding the following line in your user.rb model file:
attr_accessor :list_id
Then add the following inside your form view:
<%= f.hidden_field :list_id, :value => params[:list_id] %>
Then in your controller where you whitelist your params you would add :list_id as a secure parameter. You didn't post your strong_params method but should be like:
def user_params
params.require(:user).permit(:list_id, :name, :email, :password, :password_confirmation)
end

Rails - Register a user in stages. Starting with username

I want to change my user registration. Instead of letting the users fill in all the details at once I would like the user to fill in only the username and bring him to the registration page with the username filled in and he has to add the rest of the details.
What I have now at my landingpage (basically copy of the new user page):
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name, "Username" %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-success btn-md createbutton"%>
<% end %>
My registration page is at registation_path
<% provide(:title, 'Register') %>
<div class = "container center">
<body class ="formbody">
<center><h1>Sign up</h1></center>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-success createbutton"%>
</div>
</div>
</div>
<% end %>
</body>
I would like the user to fill in the name in 1 form at the landing page and get redirected to the registration form with the name filled in.
edit: added the controller
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update]
before_action :correct_user, only: [:edit, :update]
def new
#user = User.new
end
def index
#users = User.all
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash.now[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def create
#user = User.new(user_params) # Not the final implementation!
if #user.save
log_in #user
flash.now[:success] = "Account Created Succesfully"
redirect_to #user
else
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end

sign up and create new object at the same time

i'm new in Ruby on Rails.
I was trying to register a new user with devise and at the same time, create a new Company object. The association between them : User belongs to Company. Company has many users. I tried to make it based on this link : http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast, but it didnt work. it said : "undefined method for Company", which is Company doesnt have email attribute.
and in sign up form, i only put email attribute for user
<div class="title"><%= t('.signup') %></div>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="control-group"><%= f.label :email, t('.email') %>
<%= f.email_field :email %></div>
<div class="control-group"><%= f.label :password, t('.password') %>
<%= f.password_field :password %></div>
<div class="control-group"><%= f.label :password_confirmation, t('.password_confirmation') %>
<%= f.password_field :password_confirmation %></div>
<%= f.fields_for :company_attributes do |f_company| %>
<div class="control-group"><%= f_company.label :name, t('.company_name') %>
<%= f_company.text_field :name %></div>
<% end %>
<div class="buttons"><%= f.submit t('.signup'), class:"btn btn-primary" %><br>
<%= render "links" %></div>
<% end %>
updated
Company controller :
class CompaniesController < Devise::RegistrationsController
def new
#company = Company.new
#user = #company.users.build
end
def create
#company = Company.new(params[:company])
#user = User.create(params[:user].merge(company_id:company.id))
if #company.save
redirect_to "/"
else
render 'users/sign_up'
end
end
end
User Controller :
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to users_path
else
render 'users/new'
end
end
I would really appreciate any idea and any help. Thanks in advance
In your case, since you are only interested in receiving the company_name I'd simplify it and submit the company_name via a text_field_tag.
In other words, I would replace:
<%= f.fields_for :company_attributes do |f_company| %>
<div class="control-group"><%= f_company.label :name, t('.company_name') %>
<%= f_company.text_field :name %></div>
<% end %>
With this
<%= text_field_tag 'company_name', {placeholder:"Enter here the name of your company",class:"form-control"} %>
This would submit the name to the UsersController, and you could access it with params[:company_name] so the controller would look like this:
Users controller:
def new
#user = User.new
end
def create
#user = User.create(params[:user])
#Create a company via 'user<->company' association using 'company_name'
#company= #user.company.create(name: params[:company_name])
if #user.save
redirect_to users_path
else
render 'users/new'
end
end

Couldn't find User with id=update_password with Devise

I'm using devise on a Rails application and for various reasons I needed to add a custom password change, using solution 3 from here: https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
I've looked through various other questions and tried augmenting my routes in a number of ways but the url always comes up /users/update_password (without a parameter passed), or /users/update_password.254 (with a parameter passed). I need it to be /users/254/update_password.
Here is the Users Controller I'm working with (relevant methods are update_password and user_params).
class UsersController < ApplicationController
inherit_resources
load_and_authorize_resource
before_filter :authenticate_user!
def destroy
name = #user.to_s
destroy!(notice: "User #{#user.to_s} was deleted.")
end
def edit
#user = current_user
end
def update_password
#user = User.find(current_user.id)
if #user.update_with_password(user_params)
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
private
def build_resource_params
[params.fetch(:user, {}).permit(:name, :email, :phone_number, :password, :password_confirmation).tap do |p|
p[:institution_pid] = build_institution_pid if params[:user][:institution_pid]
p[:role_ids] = build_role_ids if params[:user][:role_ids]
end]
end
def build_institution_pid
institution = Institution.find(params[:user][:institution_pid])
authorize!(:add_user, institution)
institution.id
end
def build_role_ids
[].tap do |role_ids|
roles = Role.find(params[:user][:role_ids].reject &:blank?)
roles.each do |role|
authorize!(:add_user, role)
role_ids << role.id
end
end
end
def user_params
params.required(:user).permit(:password, :password_confirmation, :current_password)
end
end
This is the relevant portion of routes.rb
devise_for :users
resources :users do
collection do
get 'password'
put 'update_password'
end
end
This is the view I created to go with it:
<div class="page-header">
<h1>Change Password</h1>
</div>
<%= form_for(#user, :url => { :action => "update_password" } ) do |f| %>
<div class="field">
<%= f.label :password, "Password" %><br />
<%= f.password_field :password, :autocomplete => "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
And this is the link: (currently with a parameter but I've tried without as well)
<li><%= link_to "Change Password", update_password_users_path(current_user) %></li>
When I click that link I get routed to a page that says ActiveRecord::RecordNotFound in UsersController#show, Couldn't find User with id=update_password.
I tried to follow the instructions pretty closely and I've tried to fiddle with the routes a couple times to get it to work and I'm pretty lost at this point. Has anyone seen this before and can help? Thanks!
To achieve what you need, you will have the following routes:
resources :users do
patch 'update_password', on: :collection
get 'edit_password', on: :member
end
Then you'll add a link that would lead user to update password form. The link should look like as follows:
<li><%= link_to "Change Password", edit_password_user_path(current_user) %></li>
The link would lead to users/edit_password.html.erb:
<div class="page-header">
<h1>Change Password</h1>
</div>
<%= form_for(#user, :url => { :action => "update_password" } ) do |f| %>
<div class="field">
<%= f.label :password, "Password" %><br />
<%= f.password_field :password, :autocomplete => "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
<div class="action_container">
<%= f.submit %>
</div>
<% end %>
When form is submitted, that would trigger update_password in UsersController. Here is the code for controller:
class UsersController < ApplicationController
def edit_password
#user = current_user
end
def update_password
#user = User.find(current_user.id)
if #user.update_with_password(user_params)
sign_in #user, :bypass => true
redirect_to root_url
else
render "edit_password"
end
end
private
def user_params
params.required(:user).permit(:password, :password_confirmation, :current_password)
end
end

Resources