I'm trying to display commenter and body of comments model in blog application. But it is not displaying.
Here is the code of comments controller.
class CommentsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret", :only => :destroy
def create
#post=Post.find(params[:post_id])
#comment=#post.comments.create(params[:comments])
redirect_to post_path(#post)
end
def destroy
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
def check
#comment=Comment.all
end
end
//comment model
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :commenter
end
//post model
class Post < ActiveRecord::Base
attr_accessible :content, :name, :title, :tags_attributes
validates :name, :presence=>true
validates :title, :presence=>true,
:length=>{:minimum=>5}
has_many :comments, :dependent=>:destroy
has_many :tags
accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end
// comment view
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>
<p>
<%= link_to 'Destroy Comment', [comment.post, comment],
:confirm => 'Are you sure?',
:method => :delete %>
</p>
// Post view
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #post.name %>
</p>
<p>
<b>Title:</b>
<%= #post.title %>
</p>
<p>
<b>Content:</b>
<%= #post.content %>
</p>
<p>
<b>Tags:</b>
<%= join_tags(#post) %>
</p>
<h2>Comments</h2>
<%= render #post.comments %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<br />
<%= link_to 'Edit Post', edit_post_path(#post) %> |
<%= link_to 'Back to Posts', posts_path %> |
Please fix this.
<%= render #post.comments %>
is incorrect. You must render partials, not objects.
I will think that your comment view in views/comments is named show.html.erb. Try something like that:
<%= #post.comments.map do |comment| %>
<%= render 'comments/show', comment: comment %>
<%= end %>
UPD: My mistake: it's correct, description in comments.
Which file is what you call 'comment view'? To be a able to render a collection like this
<%= render #post.comments %>
you need to place a comment template to views/comments/_comment.html.erb
Of course you can place it into another partial, e.g. 'posts/_comment.html.erb` but then you'll have to be more explicit:
<%= render :partial => 'posts/comment', :collection => #post.comments %>
(Mind there is an underscore in the file name, but not in the 'partial path' passed to render)
Related
I'm adding comments for my tweets in my application but I get this error in the view for the first line in my form.
First argument in form cannot contain nil or be empty
Extracted source (around line #1): <%= form_for [#tweet, #comment] do |f| %>
My routes
resources :tweets do
resources :comments
resources :likes
end
My model
class Comment < ApplicationRecord
belongs_to :tweet
belongs_to :user
end
My controller
class CommentsController < ApplicationController
def create
#tweet = Tweet.find(params[:id])
#comment = #tweet.comments.create(params[:comment].permit(:body))
redirect_to tweets_path
end
end
My form
comments/_form.html.erb
<%= form_for [#tweet, #comment] do |f| %>
<p><%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<br>
<br>
<%= f.submit %>
<% end %>
My view (partial)
tweets/_tweets_index.html.erb
<% #tweets.reverse.each do |tweet| %>
....
<%= render tweet.comments %><br>
Add a comment
<%= render partial: 'comments/form' %>
<% end %>
In turn rendered to tweets/index.html.erb
<%= render partial: 'tweets_index' %>
I changed the first line on the form as per previous questions here ..[#foo, #bar].. as above but it still does not work. What am I doing wrong? ty
EDIT: I have made some progress but the following error appears
My form
<%= form_for( :comment , :html => {:class => "form-horizontal", :role => "form"}, url: tweets_path) do |form| %>
<p><%= form.label :body %><br>
<%= form.text_area :body %>
</p>
<br>
<br>
<%= form.submit %>
<% end %>
Error
:param is missing or the value is empty: tweet
def tweet_params
params.require(:tweet).permit(:user_id, :content, { comments: [:body] })
end
{"authenticity_token"=>"79mdlyIOZTUF8hzXhoOpzTHKhk+/5SBrfnUjnImtmek1HyXDA0U/+R6oEOYgmy4H+a2kEppasDDKBobvdpbQdg==", "comment"=>{"body"=>"Test"}, "commit"=>"Save Comment"}
What the error means is that #tweet is nil. So wherever you render this form, make sure that in the respective controller action, you define #tweet.
I'm new to Rails and struggling to get my belongs_to association right. I have an app where a painting belongs to an artist and an artist can have_many paintings. I can create and edit my paintings, however I can not edit or create artists except through the console. Through much Googling I feel I have got myself turned around. Any help would be much appreciated!
Here's my routes.rb file:
MuseumApp::Application.routes.draw do
resources :paintings
resources :paintings do
resources :artists
resources :museums
end
root 'paintings#index'
end
Here's my paintings Controller
def show
#painting = Painting.find params[:id]
end
def new
#painting = Painting.new
##artist = Artist.new
end
def create
safe_painting_params = params.require(:painting).permit(:title, :image)
#painting = Painting.new safe_painting_params
if #painting.save
redirect_to #painting
else
render :new
end
end
def destroy
#painting = Painting.find(params[:id])
#painting.destroy
redirect_to action: :index
end
def edit
#painting = Painting.find(params[:id])
end
def update
#painting = Painting.find(params[:id])
if #painting.update_attributes(params[:painting].permit(:title, :image)) #safe_params
redirect_to #painting
else
render :edit
end
end
Here's the form in my paintings view:
<%= form_for(#painting) do |f| %>
<fieldset>
<legend>painting</legend>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :image %>
<%= f.text_field :image %>
</div>
<%= form_for([#painting,#painting.create_artist]) do |f| %>
<div>
<%= f.label :Artist %>
<%= f.text_field :name %>
</div>
</fieldset>
<%= f.submit %>
<% end %>
<% end %>
Artists Controller:
class ArtistsController < ApplicationController
def index
#artists = Artist.all
#artists = params[:q] ? Artist.search_for(params[:q]) : Artist.all
end
def show
#artist = Artist.find params[:id]
end
def new
#artist = Artist.new
end
def create
#painting = Painting.find(params[:painting_id])
#artist = #painting.create_artist(artist_params)
redirect_to painting_path(#painting)
end
def destroy
#artist = Artist.find(params[:id])
#Artist.destroy
redirect_to action: :index
end
def edit
#artist = Artist.find(params[:id])
end
def update
#painting = Painting.find(params[:painting_id])
#artist = #artist.update_attributes(artist_params)
redirect_to painting_path(#painting)
end
end
private
def artist_params
params.require(:artist).permit(:name)
end
Index view:
<h1> Hello and Welcome to Museum App</h1>
<h3><%= link_to "+ Add To Your Collection", new_painting_artist_path %></h3>
<%= form_tag '/', method: :get do %>
<%= search_field_tag :q, params[:q] %>
<%= submit_tag "Search" %>
<% end %>
<br>
<div id="paintings">
<ul>
<% #paintings.each do |painting| %>
<li><%= link_to painting.title, {action: :show, id:painting.id} %> by <%= painting.artist_name %></li>
<div id = "img">
<br><%= link_to (image_tag painting.image), painting.image %><br>
</div>
<%= link_to "Edit", edit_painting_path(id: painting.id) %>
||
<%= link_to 'Destroy', {action: :destroy, id: painting.id},method: :delete, data: {confirm: 'Are you sure?'} %>
<% end %>
</ul>
</div>
In your case you should use accepts_nested_attributes_for and fields_for to achieve this.
Artist
has_many :paintings, :dependent => :destroy
accepts_nested_attributes_for :paintings
Painting
belongs_to :artist
And also you should try creating artist with paintings like this
form_for(#artist) do |f| %>
<fieldset>
<legend>Artist</legend>
<%= f.label :Artist %>
<%= f.text_field :name %>
<%= fields_for :paintings, #artist.paintings do |artist_paintings| %>
<%= artist_paintings.label :title %>
<%= artist_paintings.text_field :title %>
<%= artist_paintings.label :image %>
<%= artsist_paintings.text_field :image %>
</fieldset>
<%= f.submit %>
<% end %>
Note:
You should be having your Artist Controller with at least new,create,edit and update methods defined in it to achieve this.
Edit
Try the reverse
Artist
has_many :paintings, :dependent => :destroy
Painting
belongs_to :artist
accepts_nested_attributes_for :paintings
form_for(#painting) do |f| %>
<fieldset>
<legend>Painting</legend>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.text_field :image %>
<%= fields_for :artists, #painting.artists do |ff| %>
<%= ff.label :Artist %>
<%= ff.text_field :name %>
</fieldset>
<%= f.submit %>
<% end %>
Put this form in paintings views.
I'm trying to make a blog which has users, posts and comments. Each user can have many posts and many comments similarly each post can have many comments. I have successfully made the user and post sections but am having difficulty creating comments and then displaying them.
code:
routes.rb :
resources :users do
resources :posts do
resources :comments
end
end
user.rb :
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
post.rb :
belongs_to :user
has_many :comments, dependent: :destroy
comment.rb :
belongs_to :post, :user
I'm creating and displaying comments in the post's view itself so..
posts_controller.rb :
def show
#user = current_user
#post = Post.find(params[:id])
end
view/posts/show.html.erb :
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<% if #user.posts.comments.empty? %>
<h2>Comments</h2>
<%= render #posts.comments %>
<% end %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_user_post_path(#user.id,#post) %> |
<%= link_to 'Back to Posts', user_posts_path(#user.id) %>
comments_controller.rb :
class CommentsController < ApplicationController
def create
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #user.posts.comments.create(params[:comment])
redirect_to user_post_path(#user.id,#post)
end
def destroy
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #user.posts.comments.find(params[:id])
#comment.destroy
redirect_to user_post_path(#user.id,#post)
end
end
And the partials are:
views/comments/_form.html.erb :
<%= form_for([#user,#post,#comment]) do |f| %>
<p>
<%= #user.email %>
</p>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
I think my form_for is not right here but I'm new to rails and I've also tried form_for(#user,#post,#post.comments.build) but that didn't work either.. Anyways here's another partial:
views/comments/_comment.html.erb:
<p><strong>Commenter:</strong><%= #user.email %></p>
<p><strong>Comment:</strong><%= comment.body %></p>
<p><%= link_to 'Destroy Comment', [comment.post, comment],method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
Again here I'm having trouble with link to...any suggestions would be great.
You want to make a blog which has users , posts and comments, I see some differences between what you did and what I did it before when I was creating a blog also. I will tell you what I did (by editing the code of the files you posted in your question) then try it if it works with you :)
1- routes.rb make it like this
resources :users
resources :posts do
resources :comments
end
2- user.rb is fine no need to be modified
3- post.rb also is fine
4- comments.rb
belongs_to :post
belongs_to :user
5- posts_controller.rb
def show
#post = Post.find(params[:id])
#comment = Comment.new
end
6- view/posts/show.html.erb ( this view should make you able to see the post and the comments and a box for the new comments, and a link to edit post and a link to the posts index )
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<h2>Comments</h2>
<%= render #posts.comments %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_post_path(#post) %> |
<%= link_to 'Back to Posts', posts_path %>
7- comments_controller.rb ( don't forget to add the destroy method again )
class CommentsController < ApplicationController
before_filter :load_post
def create
#comment = #post.comments.build(params[:comment])
#comment.user_id = current_user.id
if #comment.save
redirect_to #post, notice: "Added comment."
else
render :new
end
end
private
def load_post
#post = Post.find(params[:article_id])
end
end
8- views/comments/_form.html.erb (just try to make it first in a simple way)
<%= form_for([#post,#comment]) do |f| %>
<p>
<%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
9- views/comments/_comment.html.erb
<p><strong>Commenter:</strong><%= comment.user.email %></p>
<p><strong>Comment:</strong><%= comment.body %></p>
<p><%= link_to 'Destroy Comment', [comment.post, comment],method: :delete,
data: { confirm: 'Are you sure?' } %>
</p>
I hope this work with you as it works with me, try it and let me know how it goes with you, i got my blog work from the before code for revised episode 229.
I got the answer here it is:
posts_controller:
def show
#user = current_user
#post = #user.posts.find(params[:id])
#comment = #post.comments.new
end
show.html.erb:
<p><strong>Title:</strong><%= #post.title %></p>
<p><strong>Text:</strong><%= #post.text %></p>
<% if !#post.comments.empty? %>
<h2>Comments</h2>
<%= render #comment %>
<% end %>
<h2>Add a comment:</h2>
<%= render "comments/form" %>
<%= link_to 'Edit Post', edit_user_post_path(#user.id,#post) %> |
<%= link_to 'Back to Posts', user_posts_path(#user.id) %>
comments_controller.rb:
def create
#user = current_user
#post = #user.posts.find(params[:post_id])
#comment = #post.comments.create(params[:comment])
redirect_to user_post_path(#user.id,#post)
end
comment's partial
_form.html.erb:
<%= form_for([#user,#post,#comment]) do |f| %>
<p><%= #user.email %></p>
<p><%= f.label :body %><br />
<%= f.text_area :body %>
</p>
<p><%= f.submit %></p>
<% end %>
I am working on getting multiple file uploads working for an model in my application, I have included the code below:
delivers_controller.rb
# POST /delivers
def create
#deliver = Deliver.new(params[:deliver])
process_file_uploads(#deliver)
if #deliver.save
flash[:notice] = 'Task was successfully created.'
redirect_to(#deliver)
else
render :action => "new"
end
end
protected
def process_file_uploads(deliver)
i = 0
while params[:attachment]['file_'+i.to_s] != "" && !params[:attachment]['file_'+i.to_s].nil?
deliver.assets.build(:data => params[:attachment]['file_'+i.to_s])
i += 1
end
end
deliver.rb
has_many :assets, :as => :attachable, :dependent => :destroy
validate :validate_attachments
Max_Attachments = 5
Max_Attachment_Size = 5.megabyte
def validate_attachments
errors.add_to_base("Too many attachments - maximum is #{Max_Attachments}") if assets.length > Max_Attachments
assets.each {|a| errors.add_to_base("#{a.name} is over #{Max_Attachment_Size/1.megabyte}MB") if a.file_size > Max_Attachment_Size}
end
assets_controller.rb
class AssetsController < ApplicationController
def show
asset = Asset.find(params[:id])
# do security check here
send_file asset.data.path, :type => asset.data_content_type
end
def destroy
asset = Asset.find(params[:id])
#asset_id = asset.id.to_s
#allowed = Deliver::Max_Attachments - asset.attachable.assets.count
asset.destroy
end
end
asset.rb
class Asset < ActiveRecord::Base
has_attached_file :data,
belongs_to :attachable, :polymorphic => true
def url(*args)
data.url(*args)
end
def name
data_file_name
end
def content_type
data_content_type
end
def file_size
data_file_size
end
end
Whenever I create a new deliver item and try to attach any files I get the following error:
NoMethodError in DeliversController#create
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
/Users/danny/Dropbox/SVN/railsapps/macandco/surveymanager/trunk/app/controllers/delivers_controller.rb:60:in `process_file_uploads'
/Users/danny/Dropbox/SVN/railsapps/macandco/surveymanager/trunk/app/controllers/delivers_controller.rb:46:in `create'
new.html.erb (Deliver view)
<% content_for :header do -%>
Deliver Repositories
<% end -%>
<% form_for(#deliver, :html => { :multipart => true }) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :caseref %><br />
<%= f.text_field :caseref %>
</p>
<p>
<%= f.label :casesubject %><br />
<%= f.text_area :casesubject %>
</p>
<p>
<%= f.label :description %><br />
<%= f.text_area :description %>
</p>
<p>Pending Attachments: (Max of <%= Deliver::Max_Attachments %> each under <%= Deliver::Max_Attachment_Size/1.megabyte%>MB)
<% if #deliver.assets.count >= Deliver::Max_Attachments %>
<input id="newfile_data" type="file" disabled />
<% else %>
<input id="newfile_data" type="file" />
<% end %>
<div id="attachment_list"><ul id="pending_files"></ul></div>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
<%= link_to 'Back', delivers_path %>
Show.html.erb (Delivers view)
<% content_for :header do -%>
Deliver Repositories
<% end -%>
<p>
<b>Title:</b>
<%=h #deliver.caseref %>
</p>
<p>
<b>Body:</b>
<%=h #deliver.casesubject %>
</p>
<p><b>Attached Files:</b><div id="attachment_list"><%= render :partial => "attachment", :collection => #deliver.assets %></div></p>
<%= link_to 'Edit', edit_deliver_path(#deliver) %> | <%= link_to 'Back', deliver_path %>
<%- if logged_in? %>
<%= link_to 'Edit', edit_deliver_path(#deliver) %> |
<%= link_to 'Back', delivers_path %>
<% end %>
_attachment.html.erb (Delivers view)
<% if !attachment.id.nil? %><li id='attachment_<%=attachment.id %>'><a href='<%=attachment.url %>'><%=attachment.name %></a> (<%=attachment.file_size/1.kilobyte %>KB)
<%= link_to_remote "Remove", :url => asset_path(:id => attachment), :method => :delete, :html => { :title => "Remove this attachment", :id => "remove" } %></li>
<% end %>
I have been banging my head against the wall with the error all day, if anyone can shed some light on it, I would be eternally grateful!
Thanks,
Danny
The error message indicates that params[:attachment] is nil inside process_file_uploads(), which causes params[:attachment]['file_'+i.to_s] to raise an exception.
This happens because there's no field named attachment in the form in new.html.erb.
has_many build method, Rails
Was my last question. It now works: no errors.
The new problem is that the new unit conversion doesn't associate with an ingredient ID. I thought this was "just supposed to work" from the build method?
Unit Conversion controller:
def new
#ingredient = Ingredient.find(params[:ingredient_id])
#unit_conversion = #ingredient.unit_conversions.build
end
def create
#ingredient = Ingredient.find(params[:ingredient_id])
#unit_conversion = #ingredient.unit_conversions.build(params[:unit_conversion])
if #unit_conversion.save
flash[:notice] = "Successfully created unit conversion."
redirect_to ingredient_unit_conversions_url(#ingredient)
else
render :action => 'new'
end
end
Unit Conversion Model:
class UnitConversion < ActiveRecord::Base
belongs_to :ingredient
end
Ingredient Model:
class Ingredient < ActiveRecord::Base
belongs_to :unit
has_many :unit_conversions
end
Thanks for the help, I'm finding a rough learning curve today :)
EDIT:
One more important thing..
new.html.erb
<h1> New Derived Unit </h1>
<% form_for([#ingredient, #unit_conversion]) do |f| %>
<% f.error_messages %>
<p>
<%= f.label :name %>
<%= f.text_field :name%>
</p>
<p>
<%= f.label :conversionToBase%>
<%= f.text_field :conversionToBase%>
</p>
<p>
<%= f.submit "Create" %>
</p>
<% end %>
<% link_to 'Back', url_for( :controller => 'ingredients', :action => 'show', :id => #ingredient)%>
Make sure that you have form_for [#ingredient, #unit_conversion] in your form.
new.html.erb
<% title "New Unit Conversion" %>
<%= render :partial => 'form' %>
<p><%= link_to "Back to List", ingredient_unit_conversions_path(#ingredient) %></p>
_form.html.erb
<% form_for [#ingredient, #unit_conversion] do |f| %>
<%= f.error_messages %>
<p>
... fields here
</p>
<p><%= f.submit "Submit" %></p>
<% end %>