Rails: Commenting for a Post - ruby-on-rails

I am creating a website blog and don't know what I'm going to do for adding a comment in a blog. Is there a gem or trick for that? Can you please help me and give me some tips?

There is no "trick" - you just have to code it up like the rest of your application.
Associations
Since your comments will be directly associated to your posts, it makes to start by looking at the association between the two models:
#app/models/comment.rb
Class Comment < ActiveRecord::Base
belongs_to :post
end
#app/models/post.rb
Class Post < ActiveRecord::Base
has_many :comments
end
The importance of this association is that if you want to create comments, although they'll be their own individual objects, they'll have to be "tied" to a post. The importance of this lies in the object-orientated nature of Ruby / Rails:
--
OOP
Most people don't realize that since Ruby is an object orientated language, Rails is also an object-orientated framework.
This means that you need to structure you methods, actions, etc around objects. Most beginners think you just have to create a "logical" app flow - whereas the reality is you need to build your app around the objects you hope to serve
--
Resources
Further to this, you then need to consider how you'll interact with the resources / objects in your application. I would recommend using nested resources to do this:
#config/routes.rb
resources :posts do
resources :comments #-> domain.com/posts/5/comments/new
end
The reason this is important is because of how you can then create a comment with it:
#app/controllers/comments_controller.rb
Class CommentsController < ApplicationController
def new
#post = Post.find params[:post_id]
#comment = Comment.new
end
def create
#post = Post.find params[:post_id]
#comment = Comment.new(comment_params)
end
private
def comment_params
params.require(:comment).permit(:comment, :params, :post_id)
end
end
This allows you to use the following:
#app/views/comments/new.html.erb
<%= form_for [#post, #comment] do |f| %>
<%= f.text_field :comment_attributes %>
<%= f.submit %>
<% end %>
This will help you create comment objects as a child of the post objects you want - giving you the ability to create comments for each post.
Bonus
A bonus here is that if you wanted to then nest the comments on your site, you'll want to use the Ancestry gem, as follows:
The way to do this is relatively simple. If you have a comments creation system set up, as outlined above, you'll want to add the ancestry gem to your Comment model:
#app/models/comments.rb
Class Comment < ActiveRecord::Base
has_ancestry
end
You'll need to migrate an ancestry column to your comments datatable, and then be able to populate the ancestry attribute:
You can then use the following partial to show the comments in a tree fashion:
#app/views/comments/_tree.html.erb
<ol class="categories">
<% collection.arrange.each do |category, sub_item| %>
<li>
<div class="category">
<%= link_to category.title, edit_admin_category_path(category) %>
</div>
<!-- Children -->
<% if category.has_children? %>
<%= render partial: "category", locals: { collection: category.children } %>
<% end %>
</li>
<% end %>
</ol>
You can then call it as follows:
<%= render partial: "comments/tree", locals: { collecton: #comments } %>

You could implement external comments engine, such as Disqus, or keeping it in house by making a Comment resource, which would have a relation to your post, like
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
This way you have a right way of treating your comments.
It needs some other work, controllers, views etc... But the spirit is there.

Related

Where to handle request that deal with multiple models

Example: a Survey has many Questions. A request is made to create a survey, and the request contains the survey title and metadata, plus all the questions.
This all happens on one page -- when the user clicks submit, the survey and its questions are created.
So far I have all the logic in the SurveysController but I'm not sure if this is MVC, especially because I have methods like add_question and remove_question.
Is there a preferred way of doing this?
If you're creating the questions through accepts_nested_attributes_for, then it would be okay.
--
When you mention add_question / remove question - this would be best handled in a separate questions controller (with nested resource routing):
#config/routes.rb
resources :surveys do
resources :questions, only: [:create, :destroy]
end
This allows you to use the following:
#app/controllers/surverys_controller.rb
class SurveysController < ApplicationController
def show
#survey = Survey.find params[:id]
#new_question = #survey.questions.new
end
end
#app/views/surveys/show.html.erb
<%= #survey.title %>
<% #survey.questions.each do |question| %>
<%= link_to "Remove", surveys_question_path(#survey, question), method: :delete %>
<% end %>
<%= form_for #question do |f| %>
<%= f.text_field :text %>
<%= f.submit %>
<% end %>
This would keep your controllers conventional.
Nested resources:
resources :surveys do
resources :questions # check http://localhost:3000/rails/info/routes for generated routes
end
Now you can create QuestionsController with normal CRUD actions and survey_id in params. I.e:
class QuestionsController
def create
#question = Question.new(survey_id: params[:survey_id], ... )
end
end
And to create survey with all questions at once use accepts_nested_attributes_for on Survey model http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

nested models best practice - rails

Suppose I have two models model1 and model2, and that model2 belongs_to model1 (conversely, model1 has many model2). Suppose now I want to create a model2, from the model1/1 page view, (the page showing the model1 with id 1). Here's what I did :
<%= form_for(#model2, remote: true) do |f| %>
<%= f.text_field :title %>
<%= f.submit "POST" %>
<% end %>
(#model2 was instantiated in the model1 controller show method). Is this a best practice ? Should I use nested attributes ?
What CDub said is right. However you can achieve the nested CRUD resources this way:
user = model1
post = model2
class user < ActiveRecord::Base
has_many :posts
end
class post < ActiveRecord::Base
belongs_to :user
end
In your routes you can do this:
routes.rb
resources :users do
resources :posts
end
and in your posts controller you can do this:
class UsersController < ApplicationController
def new
#post = current_user.posts.new
end
def create
#post = current_user.posts.new(params[:post])
if #post.save
redirect_to user_posts_path(current_user, #post)
else
render :new
end
end
end
You can trigger this route by doing:
<%= link_to 'new post', new_user_post_path(current_user) %>
and edit:
<%= link_to 'edit post', edit_user_post_path(current_user, #post) %>
checkout: nested resources rails api
I don't know about the best practices, but I think it makes the most sense to try and only CRUD models within their resource scope. That said, I prefer to use accepts_nested_attributes_for and creating it through a form submission to #model1, but again, it's simply preference - either will work.

nested resources and build method for making association

I have three models associated between: User, Post, Comment. Comment is nested resource with Post.
routes.rb
resources :posts do
resources :comments
end
User model:
has_many :comments
Post model:
has_many :comments
Comment model:
belonsg_to :user
belonsg_to :post
The goal is when User makes new Comment it creates association with that user. So you can see it like User knows all comments he has made.
comments_controller.rb
def create
#post = Post.find(params[post_id]
#comment = #post.comments.build[:comment]
current_user.comments >> #comment
....
end
new.html.erb
<% form_for [#post, #post.comment.build] do |f| %>
.....
<% end %>
This gives me an error no method comments. What should I make to avoid this?
Most likely you are missing "S" letter in new.html.erb. Should be comments:
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>
If there is some more logic behind you didn't post let us know. Your create action looks fine. Try to look in console student_id attribute, if its populated with ID than you are fine.cheers.
Use
#post.comments.build
Instead of
#post.comment.build (x)
this should work, if possible move this line of code from view to controller
for more info
http://guides.rubyonrails.org/association_basics.html#detailed-association-reference
In new.html.erb file, you are using "s" for build method.
It should be,
<% form_for [#post, #post.comments.build] do |f| %>
.....
<% end %>

Adding comments to specific model in rails?

Currently i am creating Blog using rails,where i want to add comments to post model. I am using acts_as_commentable,its works great on rails console but when i try to implement it in MVC,I got confused !! how can i add comments to Post model.
What should i do ? is there need to create any new controller for handle comments?
I want add comment form below the post->show view,so that user can add comments on the posts#show page.
Sorry for my english !
with acts_as_commentable as Paulo suggested or polymorphic-association
http://asciicasts.com/episodes/154-polymorphic-association
or with PRO account on railscasts: http://railscasts.com/episodes/154-polymorphic-association-revised (repo: https://github.com/railscasts/154-polymorphic-association-revised/tree/master/blog-after)
a little modified code below, this code will let you add comments to Post only as we load #commentable with #commentable = Post.find(params[:id]), if you will go through tutorial you'll be able to add comments to any other models in the app where User and Post share the same Comment model.
I used acts_as_commentable in my app before, nice gem, but I am using polymorphic-association now cause it is much more customizable.
post.rb
attr_accessible :content, :name
has_many :comments, as: :commentable
comment.rb
attr_accessible :content
belongs_to :commentable, polymorphic: true
show.html.erb
<h1>Comments</h1>
<ul id="comments">
<% #comments.each do |comment| %>
<li><%= comment.content %></li>
<% end %>
</ul>
<h2>New Comment</h2>
<%= form_for [#commentable, #comment] do |f| %>
<ol class="formList">
<li>
<%= f.label :content %>
<%= f.text_area :content, :rows => 5 %>
</li>
<li><%= f.submit "Add comment" %></li>
</ol>
<% end %>
posts_controller
def show
#post = Post.find(params[:id])
#commentable = #post
#comments = #commentable.comments
#comment = Comment.new
end
comments_controller
def create
#commentable = Post.find(params[:id])
#comment = #commentable.comments.new(params[:comment])
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
routes.rb
resources :posts do
resources :comments
end
As you can see by the acts_as_commentable documentation,
Also make sure you have the migrations to create the database structure.
In your model:
class Post < ActiveRecord::Base
acts_as_commentable
end
By your comment I see you are giving the first steps on Rails. You need to create the controller and views. In you controller you'll need to initialize the variables and call the respecting view.
My best advise for you, is before starting doing your own blog, take a look at this Rails tutorial, which will cover most of the aspects you'll need.

Field for in rails 3 not showing displaying elements inside

I have a model named Order and another model named Member and when I try to display fields from the Members model in my Orders view it doesn't even show when using the fields_for tag. Heres what my code looks like.
order model
class Order < ActiveRecord::Base
has_many :members
end
member model
class Member < ActiveRecord::Base
belongs_to :order
end
orders controller
class OrdersController < ApplicationController
def new
#order = Order.new
3.times { #order.members.build }
#title = "Order Form"
end
def create
#order = Order.new params[:order]
if #order.save
flash[:notice] = "Your order has been created"
redirect_to orders_path
else
#title = "Order Form"
render 'new'
end
end
end
The issue is in my orders view:
<% for member in #order.members %>
This displays 3 times but the information below doesn't
<% fields_for "...", member do |member_form| %>
<p>
Name: <%= member_form.text_field :name %>
</p>
<% end %>
<% end %>
For some odd reason the information in the fields for tag won't even display once. Am I missing something?
If you find out what I am doing wrong, can you please explain it to me because I am new to rails.
Thanks in advance!
The block given to a fields_for call on a collection will be repeated for each instance in the collection, essentially creating its own loop, so you don't really need to write your own explicit loop "for member in #order.members". Further, you can leverage nested_attributes functionality to enable saving of associated members directly with #order.save:
class Order < ActiveRecord::Base
has_many :members
accepts_nested_attributes_for :members
end
class Member < ActiveRecord::Base
belongs_to :order
end
In the view:
<%= form_for #order do |order_form| %>
...
<%= order_form.fields_for :members do |member_form| %>
Name: <%= member_form.text_field :name %>
<% end %>
<% end %>
And I think your controller create method should work as you have it.
See the API docs for fields_for, especially the One-to-many subsection.
I think you just need to get rid of the "...", in your call to fields_for, as fields for is expecting an object.
Try:
<% fields_for member do |member_form| %>

Resources