How to retrieve id sent from a link_to in rails - ruby-on-rails

I am trying to to edit a form through a reveal-modal. So i have multiple posts.
When I click the link 'Edit' it will reveal a div and display a form inside that is repopulated with the information. However, I don't know how to pass the post id into the form it will know which post to edit.
If i try to render the partial form I get this error:
undefined method `model_name' for Post::ActiveRecord_Relation:Class
All my information are on a controller view that is called Dashboard
controllers/dashboards_controller.rb
class DashboardsController < ApplicationController
def index
#profile = Profile.find(current_user)
#profileAll = Profile.all
#post = Post.all
end
def show
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
end
controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#profile = Profile.find(current_user)
#post = #profile.post.create(post_params)
redirect_to dashboards_path(current_user)
end
def destroy
#post =Profile.find(params[:profile_id])
#post = profile.post.find(params[:id])
#post.destroy
redirect_to dashboards_path(current_user)
end
def show
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def edit
#profile =Profile.find(current_user)
#post = #profile.post.find(params[:id])
end
def update
#post = profile.post.find(params[:id])
if #post.update(post_params)
redirect_to dashboards_path(current_user)
else
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
posts/_form2.html.erb
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited
this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :content %><br>
<%= f.text_area :content %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes.rb
Rails.application.routes.draw do
get 'homepages/index'
resources 'dashboards' do
resources 'posts'
end
#get 'users/sign_in'
resources 'profiles' do
resources 'posts'
end
devise_for :users, :controller => {:registrations => "users/registrations"}
devise_scope :user do
root :to => 'devise/sessions#new'
end
end
Dashboards/index.html.erb
<% #post.each do |post| %>
<div class="panel">
<%= #profileAll.find(post.profile_id).name %>
<hr>
<h5><%= post.title %></h5>
<p><%= post.content %></p>
<%# link_to "Edit", edit_dashboard_post_path(current_user,[post.profile, post]) %>
<%= link_to "Edit", {id: #post},'data-reveal-id' => 'edit-post' %>
</div>
<% end %>
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render 'posts/form2' %>
<a class="close-reveal-modal">×</a>
</div>

Well, it simply does not work that way. First, you have in your controller #post = Post.all and within your _form2.html.erb you want to render form for a collection. That should be:
# index.html.erb
<div id="edit-post" class="reveal-modal" data-reveal>
<%= render :partial => 'posts/form2', collection: #posts %>
<a class="close-reveal-modal">×</a>
</div>
#dashboard controller:
def index
#...
#posts = Post.all
end
_form2.html.erb:
Every #post object instance has to be replaced with form2. Read more here: http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html about rendering a collection.
However, consider a case when you have hundreds of posts. Then, for each post, a partial is rendered. That would be very inefficient so instead, consider an asynchronous request which will load only one post the user requested.

Related

In rails I can't display the new comment with iteration each do

I created a partial in post show#view which names _comments.html.erb
here it is
<p class="text-center">Poster un commentaire</p>
<%= simple_form_for [post, post.comments.new] do |f| %>
<%= f.error_notification %>
<%= f.input :content, label: "Commentaire"%>
<%= f.submit "Envoyer", class: "btn btn-primary" %>
<% end %>
and it render like that <%= render 'comments' %>
and above the partial (in post show#view) I do an iteration like that
<ul class="list-unstyled">
<% #post.comments.each do |comment| %>
<li>
<p><% comment.content %></p>
<% end %>
</li>
</ul>
But nothing appears when I create a new message, I don't userstand why.
I give your more code details
post.rb
has_many :comments, dependent: :destroy
comment.rb
belongs_to :user
belongs_to :post
The route is:
resources :posts do
resources :categories
resources :comments
end
Comments controller is
class CommentsController < ApplicationController
before_action :set_post
def create
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
if #comment.save
flash[:success] = "You commented the hell out of that post!"
redirect_to :back
else
flash[:alert] = "There is a problem with your comment"
render root_path
end
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
flash[:success] = "Comment deleted :("
redirect_to root_path
end
private
def set_post
#post = Post.find(params[:post_id])
end
def comment_params
params.require(:comment).permit(:content, :post_id, :user_id)
end
end
Thank you so much for your help.
You just missed the = in the erb template on the <p> line. Without it there won't be anything shown in the output. Also note that the </li> and end lines should be swapped so that these two blocks are not mixed together:
<ul class="list-unstyled">
<% #post.comments.each do |comment| %>
<li>
<p><%= comment.content %></p>
</li>
<% end %>
</ul>
By the way, there is another way to render collection partials like :
<ul class="list-unstyled">
<%= render :partial => "comment", :collection => #comments %>
</ul>
And there is no need to loop through the values in partial, it will manage this with the :collection parameter, and then the comment partial should be like:
<li>
<p><%= comment.content %></p>
</li>

Rails: validation on blog comments not working

I am trying to learn Rails by building a simple blog. I have made it possible to add comments with AJAX en I am now trying to validate the presence of a name and body in the comments. However, the validation is not working. When there are no errors the comment gets added like it should, but when I leave either 'name' or 'body' blank and try to add the comment, I get redirected to this weird flat HTML-version of the post I was trying to comment on (with a path like this: /posts/21/comments). I do not understand why this is happening instead of just the post page reappearing with an error message in it, and I would be very grateful to anyone that could help me out.
So here is the CommentsController:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
if #comment.errors.any?
respond_to do |format|
format.html { render #post }
format.js
end
else
respond_to do |format|
format.html { redirect_to #post }
format.js
end
end
end
def destroy
#post = Post.find(params[:post_id])
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to #post }
format.js
end
end
private
def comment_params
params.require(:comment).permit(:name, :body)
end
end
Model:
class Comment < ActiveRecord::Base
belongs_to :post
validates_presence_of :body, :name
end
And comment part of show.html.erb:
<section id="comment-section">
<div id="comments">
<h2>Reacties</h2>
<%= render partial: #post.comments.reverse %>
</div>
<%= form_for [#post, Comment.new], remote: true, authenticity_token: true do |f| %>
<% if #comment && #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
<p>
<%= f.label :name, "Naam" %><br/>
<%= f.text_field :name %></br></br>
<%= f.label :body, "Reactie" %><br/>
<%= f.text_area :body %>
</p>
<p><%= f.submit "Verstuur" %></p>
<% end %>
</section>
And the _comment.html.erb partial:
<%= div_for comment do %>
<p>
<strong>
Posted <%= time_ago_in_words(comment.created_at) %> ago
</strong>
<br/>
<i><%= comment.name %>:</i>
<%= comment.body %>
</p>
<p>
<% if logged_in? %>
<%= button_to 'Delete', [comment.post, comment],
:method => :delete,
:class=> 'link-button',
remote: true,
data: { confirm: 'Are you sure?' }
%>
<% end %>
</p>
<% end %>
Finally, my routes.rb file:
Rails.application.routes.draw do
get 'static_pages/aboutme'
get 'static_pages/photos'
get 'sessions/new'
resources :posts do
resources :comments, only: [:create, :destroy]
end
get 'admin' => 'sessions#new'
post 'admin' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
get '/overmij' => 'static_pages#aboutme'
get '/fotos' => 'static_pages#photos'
root 'posts#index'
end
The error is on this line format.html { render #post } That line renders the comments.index as they are nested with in posts so you get post/:id/comments. If you want to render a view (from another controller) you have to do it like this:
render template "posts/show"
or just
render "posts/show"
But the thing about rendering a view/template is that it will not set any variables needed, so you'll get a error like #variable is nil so you need to set the variables needed for post/show. Another thing you can do is redirect_to #post but the thing about redirect is that it will refresh the page and erase what the user had typed in the text box.
These are rails docs on rendering/redirecting
Usually I use flash to display my error messages, something like this should work
Controller
respond_to do |format|
format.html { flash[:notice] = #comment.errors, render #post }
format.js
end
View
<%if notice.present? %>
<div class="alert alert-danger" role="alert">
<% notice.each do |msg| %>
<li><%= msg %></li>
<% end %>
</div>
<% end %>

ArgumentError in Posts#edit - first argument nil

I am going through the "Getting Started with Rails Tutorial" and am stuck on update aka Edit. It is throwing the ArgumentError in Posts#edit - first argument in form can't be nil or empty. Here is the highlighted line:
First argument in form cannot contain nil or be empty
Extracted source (around line #1):
<%= form_for #post do |f| %>
It seems to have started when I implemented the partial forms part of the tutorial.
Here is the post_contoller, edit action and _forms.html respectively:
Post_controller:
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(params[:post].permit(:title, :text))
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#posts = Post.all
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :text))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Edit.html
<h1>Edit post</h1>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
_form.html
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited
this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
The error shows an ID of "7" which is the record I am trying to update.
All other functions work (show, new, delete) and BTW "new" uses the same partial form and works fine.
Any help would be much appreciated. Thanks!
U should add this in your _controller.rb
def edit
#post = Post.find(params[:id])
end
you have to pass in the post object as local. You cannot directly access instance variables defined in controller in partial. It will be nil
<h1>Edit post</h1>
<%= render :partial => 'form', :locals => {:post => #post} %>
<%= link_to 'Back', posts_path %>
In the partial
<%= form_for post do |f| %>
check below the private is used for the below function only and write all functions above this:
private
def article_params
params.require(:article).permit(:title, :text)
end

Getting undefined method `errors' for nil:NilClass

I'm doing the Ruby on Rails tutorial at http://guides.rubyonrails.org/getting_started.html
However when I get to "5.11 Adding Some Validation", after adding the error message to display when I try to create a new post from the index view I get
"undefined method `errors' for nil:NilClass"
This is the error line highlighted.
I have already created a new Post in my new action in the controller.
Here is the source
new.html.erb
<h1>New Post</h1>
<%= form_for :post, url: posts_path do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
posts_controller.rb
class PostsController < ApplicationController
def new
#Post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post= Post.find(params[:id])
end
def index
#posts = Post.all
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Thanks.
Change
#Post = Post.new
To
#post = Post.new
Subtle but deadly
You've got error in your controller:
def new
#Post = Post.new
end
just change #Post to #post.

Listing comments on the Products#index view

I have a simple app that lets users upload products and then comment on those products.
I currently have the products #show page listing the associated comments for that product. So that part works. What I cant seem to get working is, I would like to show comments for each product on the products #index page.
I was thinking that what I have working for the products#show view would also work for the #index view, but that does not seem to be the case in my situation.
comments controller
def create
#product = Product.find(params[:product_id])
#comment = #product.comments.build(params[:comment])
#comment.user = current_user
if #comment.save
redirect_to #product, notice: "Comment was created."
else
render :new
end
end
Products Controller (I'm not sure what I should be putting in the index action here. Nothing I have tried works. and #comments = #product.comments throws a noMethod error on "comments" on the productController#index action)
def index
#products = Product.all(:include => :comments)
#something about comments, nothing I've tried so far has worked
respond_to do |format|
format.html # index.html.erb
format.json { render json: #products }
end
end
def show
#product = Product.find(params[:id])
#comment = Comment.new
#comment.user = current_user
respond_to do |format|
format.html # show.html.erb
format.json { render json: #product }
end
end
Products#show view (working)
<div class="comment-wrapper">
<ul class="comments">
<%= render 'comments/comment' %>
<li>
<%= render 'comments/form' %>
</li>
</ul>
</div>
Comments partial _comment.html.erb (working in products#show not working on products#index)
<% #product.comments.each do |comment| %>
<li>
<div class="comment-inner-wrapper">
<div class="comment-controls">
<% if comment.user == current_user %>
<%= link_to [#product, comment], :method => :delete, :confirm => "Are you sure?" do %>
<i class="icon-trash"></i>
<% end %>
<% end %>
</div>
<div class="comment-author-pic">
<%= link_to comment.user do %>
<%= image_tag comment.user.image.url(:thumb) %>
<% end %>
</div>
<div class="comment-author">
<%= link_to comment.user.username, comment.user %>
</div>
<div class="comment-content">
<p><%= comment.content %></p>
</div>
</div>
</li>
Products#index view (Im hung up here. I have the form working for each product and it will post a new comment, but only visible if you go the the #show page. Comments wont render on the #index view) I get the error undefined method `comments' for nil:NilClass for line #1 of my comments partial _comment.html.erb
<div class="comment-wrapper">
<ul class="comments">
<%= render 'comments/comment' %>
<li>
<div class="comment-box-wrapper">
<%= form_for [product, Comment.new], :remote => true do |f| %>
<div class="comment-textarea">
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Comment", :class => "btn btn-small pull-right" %>
</div>
<% end %>
</div>
</li>
</ul>
</div>
All my model relationships are correct. Any help would be greatly appreciated!!!
Edit Models below
#product.rb
has_many :comments, dependent: :destroy
#comment.rb
attr_accessible :content, :product_id, :user_id
belongs_to :product
belongs_to :user
I think there is a problem with your models. Following is the sample code for products and comments that allows you to access comments for each product in index page:
#product.rb
class Product < ActiveRecord::Base
attr_accessible :name
has_many :comments
end
#comment.rb
class Comment < ActiveRecord::Base
attr_accessible :product_id, :text
belongs_to :product
end
#products_controller.rb
class ProductsController < ApplicationController
def index
#products = Product.all
end
end
EDIT If you want to use partial for comments it should be something like this.
#products/index.rb
<% #products.each do |p| %>
<%= p.name %>
<%= render 'products/comments', :product => p %>
<% end %>
#_comments.html.erb
<% product.comments.each do |c| %>
<%= c.text %>
<% end %>

Resources