RoR ruby -- undefined method `model_name' for NilClass:Class - ruby-on-rails

I'm having a trouble with the update on a class.
This is the view:
<div id = "list">
<%= form_for #list do |form| %>
<%= render 'shared/error_messages', object: form.object %>
<div class="list_fields">
<%= form.text_field :name, placeholder:
and this is the controller:
def update
if #list.update_attributes(params[:list])
flash[:success] = "List updated"
else
render 'edit'
end
redirect_to #list
end
The routes are:
resources :lists, only: [:create, :show, :destroy,:edit]
Now the problem is it keeps raising
"undefined method `model_name' for NilClass:Class"
in line 2 ---> <%= form_for #list do |form| %>
And I can't seem to figure out why.
Thanks in advance
Leo

You have to load the #list before you update its attributes.
def update
#list = List.find_by_id(params[:id])
if #list.update_attributes(params[:list])
flash[:success] = "List updated"
else
render 'edit'
end
redirect_to #list
end
And by the way, the problem you see is not caused by your update action but by your edit action that redirects to this view.
You have to load the #list in both actions. In edit action in order to render the view, in update action in order to update the appropriate object.

Related

Rails routing : nested resources

I'm running into a problem when trying to create a new object using nested resources in Rails. My routing is set up as:
resources :coins do
resources :questions
end
When I attempt to create a new question, it does not save. I'm redirected to the 'questions' page and the form from the 'new' page including everything that was typed into it remains on the page (rather than the list of questions that are supposed to be there when it saves). My controller is as follows:
class QuestionsController < ApplicationController
before_action :find_question, only: [:show]
before_action :find_coin
before_action :authenticate_user!, except: [:index, :show]
def index
#questions = Question.where(coin_id: #coin.id).order("created_at DESC")
end
def show
end
def new
#coin
#question = current_user.questions.build
end
def create
#question = current_user.questions.build(question_params)
if #question.save
redirect_to coin_question(#question.coin_id, #question.id)
else
render 'new'
end
end
private
def find_question
#question = Question.find(params[:id])
end
def find_coin
#coin = Coin.find(params[:coin_id])
end
def question_params
params.require(:question).permit(:content, :ques_num, :coin_id)
end
end
My 'new' page then displays the following form:
<%= simple_form_for #question, url: coin_questions_path(#coin.id) do |f| %>
<%= f.input :ques_num %>
<%= f.input :content %>
<%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
This is my first time using nested resources and its tripping me up a little bit. I really appreciate any assistance here.
Your create action is failing and so it's executing the else statement which is just rendering back your form with the data you entered. The easiest thing to do is to just check out the log file and see why the save it being blocked.
go to /log/development.log and if you're using a mac press Command and the down arrow which will bring you all the way to the bottom of the file.
Also you may want to check out your model validations. If you don't have flash setup or aren't outputting the errors to your view a validation may be causing the form not to save and you wouldn't see the errors.
you could add some error handling to your view like this
<%= form_with(model: question, local: true) do |form| %>
<% if question.errors.any? %>
<div id="error_explanation">
<h2 class="text-danger"><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul class="text-danger">
<% question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
for your controller try
def create
#question = Question.new(question_params)
if #question.save
flash[:success] = "question created successfully!"
redirect_to question_url(#question.id)
else
render 'new'
end
end
I think there will be error to create question.
if #question.save
redirect_to coin_question(#question.coin_id, #question.id)
else
render 'new'
end
So if record have any error to save it will redirect to new form.
Just use following code to know what is the errors to creating question
def create
#question = current_user.questions.build(question_params)
if #question.save
flash[:notice] = 'Question created'
redirect_to coin_question(#question.coin_id, #question.id)
else
flash[:notice] = 'Some error here!'
render 'new'
end
end
You need to setup flash to show flash error.

Rails remote: true undefined method in view

I have a Rails 5.0.2 app and I've managed to implement a user following system using the acts_as_follower gem. Everything works nicely, however, I'm running into some trouble adding ajax.
I'm getting the following error when clicking 'follow'
NoMethodError at /7/follow
==========================
> undefined method `followed_by?' for nil:NilClass
I have the following
users_controller.rb
def follow
user = User.find(params[:id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to user}
format.js
end
end
show.html.erb
...
<div id="follow">
<%= render partial: "users/following", locals: {user: #user} %>
</div>
...
_following.html.erb
<% if !#user.followed_by?(current_user) %>
<%= link_to follow_user_path(#user.id), remote: true do %>
<h4><span class="label label-primary">Follow</span></h4>
<% end %>
<% else %>
<%= link_to unfollow_user_path(#user.id) do %>
<h4><span class="label label-primary">Unfollow</span></h4>
<% end %>
<% end %>
I understand that I have no #user in my partial after creating the record and I can't work out how to pass it back in to the partial. Any help would be appreciated.
Silly me.
In the follow method I had this:
def follow
user = User.find(params[:id])
current_user.follow(user)
respond_to do |format|
format.html { redirect_to user}
format.js
end
end
but should have been
def follow
#user = User.find(params[:id])
current_user.follow(#user)
respond_to do |format|
format.html { redirect_to #user}
format.js
end
end
#user rather than user
your problem here is that in your controller you have user, without the "#" user is a variable that exist just in your controller method, and #user is an instance variable that can be accessed on the view.
So if you plan to use this on the view, you need to add "#" to the variable.

Ruby on Rails - Create polymorphic comment through partial

I'm currently trying to implement polymorphic comments within my app, but I'm running into problems with converting my partial form.
I was following this tutorial, step-by-step-guide-to-polymorphic-associations-in-rails, but it didn't go over this section.
Mainly, I have an Image that is commentable, and a partial at the bottom to allow users to comment on the Image.
However, when submitting the form, it can't find the #commentable object as params[:id] and params[:image_id] are both nil.
I'm having problems understanding how I'm supposed to pass this information, as the partial knows this information, but the controller does not.
// images/show.html.erb
<div class="container comment-form" >
<%= render 'comments/form', comment: #image.comments.build %>
</div>
// comments/_form.html.erb
<%= bootstrap_form_for(comment) do |f| %>
<%= f.text_area :message, :hide_label => true, :placeholder => 'Add a comment' %>
<%= f.submit 'Reply', :class=> 'btn btn-default pull-right' %>
<% end %>
// comments_controller.rb
def create
#commentable = find_commentable
#comment = #commentable.comments.build(comment_params) <<<<<
respond_to do |format|
if #comment.save
format.html { redirect_to (comment_path #comment), notice: 'Comment was successfully created.' }
format.json { render :show, status: :created, location: #comment }
else
format.html { render :new }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Error on #comment = #commentable.comments.build(comment_params)
undefined methodcomments' for nil:NilClass`
I also noticed that there is no id in the request parameters.
Parameters:
{"utf8"=>"✓", "authenticity_token"=>"xxxxxx", "comment"=>{"message"=>"nice photo"}, "commit"=>"Reply"}
Thanks for your help.
When you pass a record to a form builder rails uses the polymorphic route helpers* to lookup the url for the action attribute.
To route to a nested resource you need to pass the parent and child(ren) in an array:
bootstrap_form_for([#commentable, #comment])
# or
bootstrap_form_for([#comment.commentable, #comment])
This would give the path /images/:image_id/comments for a new record and /images/:image_id/comments/:id if it has been persisted.
You are attempting to build your comment twice. Once in the show.html, with comment: #image.comments.build and then again in your create method with #comment = #commentable.comments.build(comment_params) <<<<<
The tutorial you linked to included the private method below. If your goal is to create a comment that belongs to your Image object, the method below would look for a param with your image_id, and would return Image.find(params[:image_id])
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
You could change your show.html to pass in your image_id as a hidden param with:
<div class="container comment-form" >
<%= render 'comments/form', image_id: #image.id %>
</div>

Rails 4. Set up comment editing functionality with nested resources

I have the following models: User, Product and Comment. The user can add, edit and delete comments to the product. I've successfully set up adding and deleting functionality and now I'm struggling with editing, for some reason, it caused me a number of difficulties.
My current code returns this error when I click on the edit comment link:
NoMethodError at /products/800/comments/8/edit
undefined method `comments' for nil:NilClass
Here's how my comment model looks like:
# id :integer not null, primary key
# body :text
# created_at :datetime not null
# updated_at :datetime not null
# user_id :integer
# product_id :integer
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :product
# validations ...
end
In User model I have has_many :comments and in Product - has_many :comments, dependent: :destroy.
In my routes.rb file I have the following nested resources:
resources :products, only: [:show] do
resources :comments, only: [:create, :edit, :update, :destroy]
end
My ProductsController has the only method show and nothing else, and here's how it looks like:
def show
product = Product.find(params[:id])
photos = ProductsPhoto.where(product: product)
case product.products_category.name
when 'Violin'
#product = [product, Violin.where(product: product).first, photos]
when 'Guitar'
#product = [product, Guitar.where(product: product).first, photos]
when 'Saxophone'
#product = [product, Saxophone.where(product: product).first, photos]
when 'Piano'
#product = [product, Piano.where(product: product).first, photos]
end
#comment = Comment.new
#comments = Comment.where(product_id: product.id).order('created_at DESC')
end
And now here's my CommentsController, which has create, edit, update and destroy:
class CommentsController < ApplicationController
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.create(comment_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to #product, notice: 'Comment Created!'
else
redirect_to #product, notice: 'Something went wrong...'
end
end
def show
end
def edit
#product = Product.find(params[:product_id])
#comment = #product.comments.find(params[:id])
end
def update
#product = Product.find(params[:product_id])
#comment = #product.comments.find(params[:id])
respond_to do |format|
if #comment.update_attributes(comment_params)
format.html do
redirect_to [#comment.product, #comment], notice: 'Comment Updated!'
end
else
format.html { render action: 'edit', notice: 'Something went wrong...' }
end
end
end
def destroy
#product = Product.find(params[:product_id])
#comment = #product.comments.find(params[:id])
#comment.destroy!
redirect_to #product, notice: 'Comment Deleted!'
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
My _form view is located at views/products/_form.html.erb and looks like this:
<%= simple_form_for([#product[0], #product[0].comments.build]) do |f| %>
<%= f.error_notification %>
<%= f.input :body, required: true, placeholder: 'Type in your comment...', input_html: { class: 'form-control'}, label: false %>
<%= f.button :submit, class: 'btn btn-primary btn-block' %>
<% end %>
And in the views/products/show.html.erb I render the partial of comments and there are the links for destroying and editing the comment, they look like this:
<%= link_to edit_product_comment_path(comment.product, comment) do %>
<span class="glyphicon glyphicon-pencil"></span>
<% end %>
<%= link_to [comment.product, comment], method: :delete do %>
<span class="glyphicon glyphicon-remove"></span>
<% end %>
the delete link works fine and the edit link doesn't.
Maybe I've mistaken with routes, here're the routes for comments:
product_comments POST /products/:product_id/comments(.:format) comments#create
edit_product_comment GET /products/:product_id/comments/:id/edit(.:format) comments#edit
product_comment PATCH /products/:product_id/comments/:id(.:format) comments#update
PUT /products/:product_id/comments/:id(.:format) comments#update
DELETE /products/:product_id/comments/:id(.:format) comments#destroy
In my views/comments/edit.html.erb I render the same form:
<%= render 'products/form' %>
however, when I click on the edit link, I get the following error:
NoMethodError at /products/800/comments/8/edit
undefined method `comments' for nil:NilClass
at the very first line of the _form.html.erb.
I hope I've provided enough information to describe the problem.
So, could you please help me with resolving that issue with comments editing?
It's too early this morning...
This is not correct :
<%= simple_form_for([#product, #product.comments.build]) do |f| %>
Try :
<%= simple_form_for [#comment.product_id, #comment], url: product_comment_path(#comment.product_id, #comment) do |f| %>
Added section
(All of this is assuming that we are working with a single #comment, not the #comments collection. Based on your comments about the delete working.)
To reply to your comment, yes, absolutely you do need separate forms for "new" versus "edit" action for your child table, comments.
Form "new" naming convention is comments/_form.html.erb, the "edit" form would be comments/_form_edit.html.erb,
I would open the "new" action form for comments...
<%= simple_form_for([:product, #comment]) do |f| %>
And the "edit" action...
<%= simple_form_for [#comment.product_id, #comment], url: product_comment_path(#comment.product_id, #comment) do |f| %>
Sorry I forgot the URL on the previous version, I have updated the code snippet above to reflect this change as well. Caveat: There may be other ways to construct this link, but this is how I have implemented the case of having a product (parent) with reviews/comments (many children).
Nested attributes
In further response to your comment, I believe some of what you're looking for could be achieved by using nested attributes in forms. This is another topic. I would get the new/edit form simple cases working and then add complexity.

undefined method `errors' for nil:NilClass

Here is my Edited details:
I have my controller like,
class Enr::Rds::SurvRdsapXrefsController < Enr::Controller
def index
#enr_rds_surv_rdsap_xrefs = Enr::Rds::SurvRdsapXref.paginate(page: params[:page])
end
def show
end
def new
#enr_rds_surv_rdsap_xref = Enr::Rds::SurvRdsapXref.new
end
def edit
#enr_rds_surv_rdsap_xref = Enr::Rds::SurvRdsapXref.find(params[:id])
end
def create
#enr_rds_surv_rdsap_xref = Enr::Rds::SurvRdsapXref.new(params[:enr_rds_surv_rdsap_xref])
respond_to do |format|
if #enr_rds_surv_rdsap_xref.save
format.html { redirect_to :enr_rds_surv_rdsap_xrefs, notice: "Survey link was successfully created." }
format.js
format.json { render json: #enr_rds_surv_rdsap_xref, status: :created, location: #enr_rds_surv_rdsap_xref }
else
format.html { render action: "new" }
format.js
format.json { render json: #enr_rds_surv_rdsap_xref.errors, status: :unprocessable_entity }
end
end
end
def update
end
def destroy
end
end
Here is my view form like
<%= form_for(#enr_rds_surv_rdsap_xref, :remote => true) do |f| %>
<% if #enr_rds_surv_rdsap_xref.errors.any? %>
<div id="error_explanation">
<div class="validate">
The form contains <%= pluralize#enr_rds_surv_rdsap_xref.errors.count, "error") %>.
</div>
<ul>
<% #enr_rds_surv_rdsap_xref.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="control-group">
<%= f.label :section %><br />
<%= f.text_field :section %>
</div>
<%= f.submit %>
<% end %>
When i click the index page to create a new link, the index page showing error like
NoMethodError in Enr/rds/surv_rdsap_xrefs#index
undefined method `errors' for nil:NilClass
Thanks for the suppport and please suggest me to rectify the error. I am new to ROR. Thanks
Your error reveals that the rendering of the index template is causing the error, which means you're rendering the form for the new survey (the code snippet above) in the index template. This is fine, but if you're going to do that, you'll have to instantiate a new survey in index, as well as in new.
At the simplest, you could just copy the code in new to index:
def index
#enr_rds_surv_rdsap_xrefs = Enr::Rds::SurvRdsapXref.paginate(page: params[:page])
#enr_rds_surv_rdsap_xref = Enr::Rds::SurvRdsapXref.new
end
def new
#enr_rds_surv_rdsap_xref = Enr::Rds::SurvRdsapXref.new
end
To keep your code a bit DRYer you might change where the new instance is created. A pattern you'll often see is something similar to:
before_filter :build_record, :only => [:new, :index]
protected
def build_record
#survey = YourSurvey.new
end
This way you don't even need to write the new/index methods if you don't have any other logic.
Do you also set #survey in the new action in your controller? The error means that when the view is rendered #survey is nil, so there must be a problem with setting that instance variable.
Do you get the error when you go to the 'new' view or when you try to submit the form (create)?
The form contains <%= pluralize#enr_rds_surv_rdsap_xref.errors.count, "error") %>
This line of the code is the problem. You are lacking a "(" between the pluralize and the #enr...
Explained: RoR thinks that the object is: pluralize#enr... instead of the # All alone, and he has no errors for this kind of object.

Resources