Updating a record via a action method - ruby-on-rails

User signs up, is redirected to a page to be collected info, pretty straight forward
I for my life can't figure out how to do this
My controller for the user
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.find session[:user_id]
#user = User.update(user_addinfo)
redirect_to user_path
end
def create
#user = User.new(user_params)
if #user.save
#session[:user_id] = #user.id
#UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path
flash[:success] = "Welcome to InYourShoes!"
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def user_addinfo
params.require(:user).permit(:year)
end
end
user_addinfo is the action method that i want to call updating my record on for my additional_info method.
the def create method has commented line that i'm unsure if necessary, particularly the session[:user_id] = #user.id. I was told that i need this in order to keep track of my session, but perhaps someone can debunk this for me, as im following michael hartl's tutorial.
as of right now with this code, rails is giving me a parameter missing in the
params.require(:user).permit(:year) line.
Much help is greatly appreciated. Ive been trying many different things, and cant seem to figure this out

Change your controller code as below:
def additional_info
#user = User.find params[:id] ## Set #user
end
def update
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
def create
#user = User.new(user_params)
if #user.save
#session[:user_id] = #user.id
#UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path(#user) ## Pass #user
flash[:success] = "Welcome to InYourShoes!"
else
render'new'
end
end
and in your routes.rb update the additional_info route as
get 'info/:id' => 'users#additional_info', :as => 'additional_info'

You additional_info action seems to be wrong. You need to pass in the id of the user for whom you are collecting additional information.
def additional_info
#user = User.find params[:id]
#user.update_attributes(user_addinfo)
redirect_to user_path(#user)
end

The line you have commented in your create method:
#session[:user_id] = #user.id
Is what is storing the user id to a session variable and not a param in the url.
You then have this line commented in your additional_info method
#user = User.find session[:user_id]
This is looking up the user by the id that you would have previously stored in the session variable.
At that point the user object would be stored in user
If you need it in your instance variable, make sure to modify the line to be
#user = User.find session[:user_id]
Your user would then be stored in #user and be able to be accessed in the view

Related

What does redirecting to an instance mean in Ruby on Rails

What does redirecting to a particular instance mean? I am aware of how the redirecting works.
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#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
def edit
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
I understand the following ways of redirecting:
redirect_to :new (redirect to new method and displaying the new.html.erb file)
redirect_to "show" (redirect to show.html.erb file or the path for show method)
but what does redirect_to #user mean? Which method and path are we are redirecting to?
If you check the redirect_to documentation, you will find this.
Record - The URL will be generated by calling url_for with the options, which will reference a named URL for that record.
It's Rails "magic" for redirecting to the #show action for that #user using GET. You'll find similar things in default Rails forms as well, but for actions like POST.
According to section 7.4.1 from Michael Hartl's The Rails Tutorial:
redirect_to #user
can be written instead of
redirect_to user_url(#user)
Quoting Michael Hartl:
This is because Rails automatically infers from redirect_to #user that
we want to redirect to user_url(#user).

Redirect_to in model after error

I have a function in my model to import data from a CSV file and I'd like to have validations should there be any errors. For example, when I upload the file, I search for a User based on an ID in the file. If there is no User with that ID, I'd like to redirect_to a different page with an error.
def self.getUser(scale_id)
#user = User.find_by(scale_id: scale_id)
if #user == nil
redirect_to users_path
else
return #user
end
end
def self.bulk_upload_weigh_ins(file)
output = []
errors = []
CSV.foreach(file.path, headers: true, ) do |row|
row = row.to_hash
#scale_id = row["scale_id"]
#user = getUser(#scale_id)
row.merge!(user_id: #user_id)
WeighIn.create! row.to_hash
end
end
...and no matter what path I put there, I get the following: undefined local variable or method 'users_path' for #<Class:0x007fa06f466998> even when it is a valid path.
Is there something wrong with redirecting like this? If yes, how should I do it?
The cleanest way for custom validations is to do something like:
In your model:
User < ActiveRecord::Base
validate :get_user
def initialize(params={})
self.id = params[:id]
end
def get_user
#user = User.find_by(self.id)
if #user.nil?
errors.add(:base, "Invalid User")
return false
else
return #user
end
end
In your controller you'd then do:
def whatever_action_youre_using
#user = User.new(user_params)
unless #user.valid?
redirect_to users_path
end
end
def user_params
params.require(:user).permit(:first_name, :email, :etc, :whatever_your_atts)
end
I have a function in my model that is searching for a User based on an
ID
undefined local variable or method 'users_path' for
Class:0x007fa06f466998
As #Dave Newton mentioned in the comments, the path helpers are not available in models unless you specifically include them. Also you can't and never need to use redirect_to in a model. The application logic should be moved to the controller. Something like below should work
def get_user
#user = User.find_by(scale_id: params[:user][:scale_id])
if #user.nil?
redirect_to users_path, notice: 'Your error message here'
else
return #user
end
end

redirecting from another page taking info

So after the user signs up, i redirect them to my additional info page where i collect some more information. However, something is wrong with my design/implementation as rails is saying im missing users/create template
this is my users controller
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.new(user_addinfo)
if #user.save
redirect_to show_path
end
end
def create
#user = User.new(user_params)
if #user.save
# UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path
flash[:success] = "Welcome to InYourShoes!"
#return #user
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def user_addinfo
params.permit(:year)
end
end
def show is the user profile page i want to show after redirecting to the additional_info page
def additional_info is just take additional info from the private method def user_addinfo
def create is the sign up process.
After entering the basic user info, it gets redirected to additional which is fine. but after the additional, it says im missing the users/create template, but my code i attempted to redirect to show_path and #usersshow, still doesnt work
any suggestions? sorry if this seems intuitive but Im new to rails.
I think your problem is in the additional_info method, as i said in the comment. What you're doing is:
creating a user
creating a session for the user (sign_in #user) - storing somewhere the user_id in the session
redirecting to your additional_info page
And here comes the problem. As the user is already signed in you don't have any need to create a new user with additional params. You should have some helper to retrieve the current signed in user (like current_user) and in additional_info method, just update it.
So your additional_info method would become something like:
def additional_info
user = User.find session[:user_id]
user.update params[:user]
redirect_to user_path #show action
end

undefined method `update_attributes'

I have look around and I'm not sure how to fix this problem. I have a undefined method `update_attributes'. I'm thinking it's because #user is not defined. So if I am able to define #user it should be able to fix it. The thing is I don't know how to define #user in order to fix it. If someone could point me in the right direction that would be great.
Users.controller.rb:
def edit
#user = User.find(params[:id])
end
def update
#user.update_attributes(params[:id])
flash[:success] = "Account updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
If you are using restful paths for your resources then update action should be something like this:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Account updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
We essentially first find the user record through the params[:id] and then update the user fields.

using redirect and if multiple times

My question is actually fairly simple, how do I make a create action which checks if a user is logged in, and if she/he is then redirect to the dashboard instead of rendering the index page where they've got links and stuff to go to and sign up. Also why is the code below not working.
class UsersController < ApplicationController
def new
#user = User.new
end
def create
if current_user.nil?
redirect_to dplace_index_path
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end
end
end
end
Your code isn't doing what you expect because the if statements are actually nested (you want elsif with this same structure -- or see my suggested fix below). Here's what your code, when properly formatted, actually looks like:
def create
if current_user.nil?
redirect_to dplace_index_path
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end
end
end
Logically, you will never get down into the second if statement, because current_user must be nil to enter the first. Try something like this instead:
def create
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
else
redirect_to dplace_index_path
end
end
I rearranged the code, but it should logically do what you want now. I put the "happy path" first (the current_user exists), and moved the redirect into the else statement.
General user authentication:
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to dashboard_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
Try:
def create
if current_user.blank? # .blank? will check both blank and nil
# logic when user is not logged in
redirect_to index_path
else
# logic when user is logged in
redirect_to dashboard_path
end
end
def create
redirect_to dplace_index_path unless current_user
# no need to check current_user again
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end

Resources