Rendering template from another controller causes NoMethodError - ruby-on-rails

I'm working on a rails app that contains a Users controller and an Images controller. This is the create method in the Images controller:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
render 'users/show' #Error occurs here
end
end
Successful saves are handled fine, but if the image is too large or non-existent and 'users/show' is rendered, rails gives the error:
NoMethodError (undefined method `name' for nil:NilClass):
app/views/users/show.html.erb:1:in `_app_views_users_show_html_erb___2850090823537495038_37901140'
app/controllers/images_controller.rb:12:in `create'
I expect this happened because I hadn't initialized all the variables necessary for 'users/show' within my Images controller, so I moved the content from the show method of the Users controller to a new method in the Application controller and called it before rendering the page from Images. Here's the intitialize method:
def initialize_show
#user = User.find(params[:id])
#images = #user.images.paginate(page: params[:page])
#image = current_user.images.build if logged_in?
end
And the new create method:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
initialize_show # Called this method
render 'users/show'
end
end
Now rails is giving the error:
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=):
app/controllers/application_controller.rb:6:in `initialize_show'
app/controllers/images_controller.rb:12:in `create'
What am I missing here? This is my first rails app so I appreciate the help.

ptd provided the answer in a comment above. #user wasn't getting initialized because the id param wasn't posted to images#create. Here's the solution:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
#user = current_user
initialize_show # I removed the #user initialization in this method
render 'users/show'
end
end

It looks like your template (users/show) uses something (#vars) that is not available in this case. Can you show that template code? Maybe you have something line #user.name there but this var is not initialized in case you have described...

Related

NoMethodError in UserController#register undefined method `save' for nil:NilClass

Trying to learn ruby on rails following Michael Hartl's tutorial, when I try to go to the registration page in the book I get this:
NoMethodError in UserController#register
undefined method `save' for nil:NilClass
here is the code from the user_controller.rb file:
class UserController < ApplicationController
def index
#title = "RailsSpace User Hub"
end
def register
#title = "Register"
if request.post? and params[:user]
#user = User.new(user_params)
end
if #user.save
flash[:notice] = "User #{#user.screen_name} created!"
redirect_to :action => "index"
end
end
private
def user_params
# Add the user attributes that you sent with post (form) to the permit
method.
params.require(:user).permit(:name, :screen_name)
end
end
It's complaining about line 11 where it says: if #user.save I'm just following the tutorial I don't know what's going on.
Try to understand what the error message is saying. You're trying to call .save on #user but where you are calling it, #user may not be defined. The problem is you can't call .save on a nil object so it throws NoMethodError.
You're logic is incorrect so you must first make sure #user is instantiating a new User instance. It should be more like this:
def register
#title = "Register"
if request.post? && params[:user]
#user = User.new(user_params)
if #user.save
flash[:notice] = "User #{#user.screen_name} created!"
redirect_to :action => "index"
else
# handle erorrs here
flash[:alert] = "Please fix errors: #{#user.errors.full_messages.inspect}"
redirect_to :back #this may need to change depending, just an example.
end
end
end
NoMethodError in UserController#register undefined method 'save' for nil:NilClass
The error is thrown because you are calling save on a nil; and it is because nil object does not have this method. the save is a instance method belonging to ActiveRecord::Base class.
The reason #user is nil is because #user is an instance variable in the UserController class which you have not given it any value. Any variable starting with # inside a class is an instance variable in Ruby.
To solve this problem, you should set a value to #user, and in this case it should be a User instance. You can either create a new user object by doing #user = User.new(user_params) or you fetch a record from the Database by doing #user = User.find(<some_id>)

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).

Getting Data from API (ok 200 Response Undefined Method 'id')

I got the below to work and call up membership data based on current_user.id (See 200 Ok response) this shows up in my logs.
GET https://api-e1.authrocket.com/v1/memberships?user_id=usr_0vKhXTr0K1bz6kUipKNnjD
-> 200 (103.4 ms)
NoMethodError (undefined method `id' for #<NCore::Collection:0x007f50c82a7e50>):app/controllers/directory/categories_controller.rb:13:in `index'
I was using current_user.id which worked.
#directory_category.user_id = current_user.id
Trying to change it so it grabs the user's membership.id
#directory_category.user_id = membership_info.id
The full create statement I'm working with.
# Create
def create
#directory_category = Directory::Category.new(directory_category_params)
#directory_category.user_id = membership_info.id
if #directory_category.save
redirect_to directory_categories_path, notice: 'Category was successfully created.'
else
render :new
end
end
# Directory Category Index
def index
#directory_categories = Directory::Category.where(user_id: membership_info.id)
end
My attempt, which does say 200 ok getting current_user id and putting it at the end AuthRocket::Membership.all statement like below:
def current_user
#_current_user ||= AuthRocket::Session.from_token(session[:ar_token]).try(:user)
end
def membership_info
AuthRocket::Membership.all user_id: current_user.id
end
https://authrocket.com/docs/api/memberships
It looks like your
def membership_info
AuthRocket::Membership.all user_id: current_user.id
end
method is actually returning a collection and not a single item. if you change it to
def membership_info
AuthRocket::Membership.all(user_id: current_user.id).first
end
or whichever record you actually want, you should stop this error from raising.

Rails4: losing form validation errors while using `redirect_to` in controller

I've been trying to fix this for a while but haven't gotten anywhere yet. Would appreciate if someone could let me know how how this can be done, or if there is any way i can use the render method to do this instead (currently preserves errors but redirects to wrong path as mentioned below...)
I have a custom route for form which I am trying to redirect back when there are validation errors:
get "clubs/sign_up/:plan_id", to: "clubs#new", as: :new_membership
below is what I have so far in my controller along along with some comments regarding other steps I have tried
clubs_controller.rb
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = "Please check form errors:"
redirect_to new_membership_path(session[:membership_plan_id]) #errors lost
# render action: 'new', plan_id: 'silver' # <<<Preserves errors but breaks path, renders: localhost:3000/clubs instead of .../clubs/sign_up/:plan_id
# session[:membership_errors] = #membership.errors #<<< Doesn't wotk either, getting a cookie overflow error when trying to pass errors to #new
return
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new
end
Assuming plan_I'd is part of your model..
Change your render line to:
render :new
Change the rest to:
def new
session[:membership_plan_id] = params[:plan_id]
#membership = Membership.new plan_id: params[:plan_id]
end
def create
#membership = Membership.new(membership_params)
if #membership.save
redirect_to root_path
else
flash[:error] = #membership.errors.full_messages.to_sentence
render :new
end
end
And add a hidden field for plan_id in your form. The reason render goes wrong is that it does not have the param available, trying to add it to the render operation does not work hence your issue
You need to render instead of redirecting. Use the ||= operator to help here.. It's all just ruby, so something like
(..snip..)
else
flash[:error] = "Problem with form"
new
end
end
def new
session[:membership_plan_id] = params[:plan_id]
#membership ||= Membership.new
render 'new'
end

While using session based model , getting error "undefined local variable or method session for " in rails

code which giving error is in CommentsController
if #comments.save
user_session.add_comment(#comments) // this is cause of error
# session[:comment_ids] ||= []
# session[:comment_ids] << #comments.id
flash[:notice] = "Comment Successfully created"
redirect_to #post
else
redirect_to :back
end
When I go to edit comment which is stored in session for 1 minute. I got this error:
NameError in CommentsController#create
undefined local variable or method `session' for #<UserSession:0xaca0684>
add_comment is defined in session model.
One more thing I want to say that error occurs because I used a centralized location through session model otherwise commented code above was working fine.
If I understand correctly, you've refactored the commented out code into the user_session object.
If you read the error message you see that the error references a variable session for #<UserSession:0xXXXXX>. From this I understand that you tried to reference the session object from within the UserSession class, but you did not pass it to the user_session object.
You should add it to the method's signature, and use it like this:
class UserSession
def add_comment(session, comment)
session[:comment_ids] ||= []
session[:comment_ids] << comment.id
end
end
And in your controller:
if #comment.save
user_session.add_comment(session, #comment)
flash[:notice] = "Comment Successfully created"
redirect_to #post
else
redirect_to :back
end

Resources