I have a rails app with a Blog and comments, each blog post has many comments. In each blog (show action) I can submit a comment on at form. My question is I need to associate the blog_id in comments with the blog I am viewing, I could pass this as a hidden view but I am asking for the BEST way to do this, maybe a helper I am unaware of.
<h3>Leave a reply</h3>
<% #blog.comments.each do |comment| %>
<p>
<%= comment.text %>
</p>
<% end %>
<%= form_for(Comment.new) do |f| %>
<%= f.text_field :name %>
<%= f.text_area :text %>
<%= f.hidden_field :blog %>
<%= f.submit %>
<% end %>
When you initialize a new comment, initialize it through a blog instance.
def show
#blog = Blog.find(params[:id])
#comment = #blog.comments.build
end
Then, in your form, you want to use the comment instance instead of initializing a new comment:
<%= form_for(#comment) do |f| %>
Assuming you have the correct relationships the comment will automatically have the blog id.
In the create action you will want to ensure the comment is also created through the blog instance.
def create
#blog = Blog.find(params[:id])
#comment = #blog.comments.build(comment_params)
if #comment.save
# etc ...
end
Although associating a comment with a blog may not be a good design decision depending on what you want to do, unless by blog you mean a post.
Related
I am rendering a collection of Posts:
In posts_controller.rb:
def show
#posts = Post.where("user_id = ?", id)
end
In show.html.erb:
<ol>
<%= render #posts %>
</ol>
In _post.html.erb:
<%= form_for [post, #comment] do |f| %>
<%= f.text_area :content %>
<%= f.submit "Post" %>
<% end %>
The form_for in _post.html.erb is so someone can add a comment to any of the rendered posts. Comments are also of class Post. This means in the posts_controller I need something like #comment = Post.new(post_params) for the form in the partial. If I were only rendering a single Post this wouldn't be a problem. However, I am rendering a collection of Posts, each of which needs a #comment instance variable passed to it. How do I create a #comment instance variable in the posts_controller for each post? And how do I pass these #comments to the partials? And what's the correct code in form_for in the partial?
You should explicitly build the comment for each post like below,
def show
#posts = Post.where("user_id = ?", id)
#posts.each{|post| post.comments.build}
end
and use the same in form,
<%= form_for [post, post.comments.last] do |f| %>
<%= f.text_area :content %>
<%= f.submit "Post" %>
<% end %>
This will build the comment for every post while rendering the page, which can be accessed by post.comments.last. Comment won't exist in database until the comment form associated with post is submitted.
Note: Need to modify post.comments.last if default scope is changed http://apidock.com/rails/ActiveRecord/Base/default_scope/class
You should specify that each post contains a/many comment and build those
class Post
attribute :comments, type:Comment, typecaster: Comment, default: []
end
Class Comment
end
Now in the form you can simply render using
<%=#post.comments%>
PS : Do not keep comment as a post type if you want to avoid rendering comments for comments and so on.(You can use the same type as well)
I have created a simple form to create an instance of a modle and for some reason it is not calling the create method in the controller. Here is the form code:
<% #house.mates.each do |mate| %>
<p><%= mate.name %></p>
<% end %>
<h2>Add a new mate:</h2>
<%= form_for #mate do |f| %>
<p><%= f.label "Name" %>
<%= f.text_field :name %>
<%= f.hidden_field :house_id %>
</p>
<%= f.submit "Submit", :action => :create %>
<% end %>
Here is the controller code:
class MatesController < ApplicationController
def new
#mate = Mate.new
end
def create
#mate = Mate.new(params[:mate])
#mate.save
redirect_to house_path(current_house)
end
end
There is a many to one relationship between the Mate model and the House model... I am fairly new to rails but I have made other apps with similar forms, and I have never had this problem before. I can create and save Mate objects in the console, and I am not getting any errors, so it seem that somehow the controller method is not being called. Any help is much appreciated!
In fact, if other things have no problem, your #mate object should be created. You just can't see it in house page because you have not associated #mate with house in your code.
In your form you referred :house_id, but this attribute is nil when you rendering the form.
The reason is you have not assigned it in controller.
In controller you need to initialize #mate from house object to have house_id inside it
def new
#house = something
#mate = #house.mates.new # Instead of Mate.new
end
I have a page with many posts, and each post has a list of comments. At the end of the list is a form for a user to add a comment. Only one comment can be submitted at a time.
Can I get away with something like:
form for #comment
...
form for #comment
or do I need to specifically make sure each form is for a separate object? ie
form for #comment1
...
for for #comment2
If it's the latter, how can I make the main page's controller create one comment object for every post on the page?
You need something like this on your view
<% #posts.each do |post| %>
...
<%= form_for post.comments.build do |f| %>
<%= f.hidden_field :post_id %>
...
<% end %>
<% end %>
or, if you use nested resources in you routes
<% #posts.each do |post| %>
...
<%= form_for [post, Comment.new] do |f| %>
...
<% end %>
<% end %>
You can use Nested model form for this purpose.
Im looking for the following thing: an array of all users (only 6 in this case) with a checkbox in front of their name, resulting in a list of selectable players for the game.
Current code:
<%= form_for #game, url: games_path, :method => "post" do |f| %>
<%= f.label :name %>
<%= f.text_field :name, :value => "#{current_user.name}\'s Game" %>
<%= f.fields_for :participants do |ff| %>
<%= ff.label :user_id %>
<%= ff.text_field :user_id %>
<%= ff.check_box :user_id %>
<% end %>
<%= f.submit "Create Game", class: "btn btn-primary" %>
<% end %>
I'm now having 3.times { #game.participants.build } in my controller which effectively gives me 3 textfields in which i can fill in the participant id in order to make a record in the table participants (which is linked to games).
I've been looking around for 1.5h now and i cant seem to find a proper answer. What i need is a syntax that gives me a list of all current users (say #users) with a checkbox attached to it. When I click the checkbox it should add its id to the parameters and i should be able to create a new game with the linked participant id's. However I'm getting some problems with the ID's attached to the check_box which always seems to be 1. I've read some stuff about checkboxes being a pain with hashes, but I have no other solution atm.
I tried:
<% #users.each do |i| %>
<%= check_box_tag "alternate_numbers[#{i}]" %> <%= i.name %><br />
<% end %>
But i see no way to get that fixed up part of the form itself.
GamesController code (edit):
def new
#users = User.paginate(page: params[:page])
#games = current_user.games
#game = Game.new
3.times { #game.participants.build }
end
def create
#game = Game.new(params[:game])
#newround = #game.rounds.new
#newround.storyFragment = "New story!"
if #game.save && #newround.save
flash[:success] = "Created!"
redirect_to game_path(#game.id)
else
redirect_to root_url
end
end
It's very vague to describe since im not exactly sure how to accomplish this.
In short: the check_box should contain the value of the user_id in the loop. I'm now filling in a manual ID with the text_field helper but i'd like to have the checkbox linked to the username that is right next to it in the view.
Any guidelines/solutions/tips?
Thx
Okay, so you're making a form for a new Game. You now have to feed that new Game, along with some Participants to your view.
def new
#game = Game.new
#participants = User.all # or the users you want
end
Now use those in your view. You were on the right track. Depending on how your create action works:
<% #participants.each do |p| %>
<%= check_box_tag "participants[#{p.id}]" %> <%= p.name %>
<% end %>
I think what you were missing was the documentation for check_box_tag. The input attribute name is the argument.
You also seem to have a lot of logic in your controllers. Remember to keep the logic in the models, and only use the controllers to give the right objects to your views, and taking them for saving, for example. As the saying goes, "fat model, skinny controller".
I have a model that I want to be commentable. I am having difficulty creating a form on my model's 'show' view that will allow comments to be created. I am not finding any good or useful examples. Can anyone point me to or show me an example of how to do this?
Example:
A simple blog application. I have a model called Post. It is commentable. So on the 'show' view I want to show a Post and, at the bottom, have the fields that, when completed and submitted, create a new comment associated with the post and put it in the database.
Sounds straightforward and I have it working so I can display comments that I have seeded. I just can't get a form to work to put new ones in. Any help is appreciated.
Lets assume a Post model. Make sure, you have
class Post < ActiveRecord::Base
acts_as_commentable
end
then in the view of say Post#show
<%= form_tag "/posts/add_new_comment" do %>
<%= hidden_field_tag "id", post.id %>
<%= text_area_tag "comment[comment]" %>
<%= submit_tag "Post Comment" %>
<% end %>
then in the PostController
def add_new_comment
post = Post.find(params[:id])
post.comments << Post.new(params[:comment])
redirect_to :action => :show, :id => post
end
and in routes.rb
match "/posts/add_new_comment" => "posts#add_new_comment", :as => "add_new_comment_to_posts", :via => [:post]
Hope this gets u up and running.
This is very, very basic stuff and you clearly need some better structure and approach to your learning. Buying a book, such as Agile Web Development with Rails, is the only real way to learn, otherwise you'll wander from problem to problem without ever actually learning anything well.
Say you have a post that you want to comment.
#routes.rb
map.resources :posts do |post|
post.resources :comments
end
#post_controller.rb
def show
#post.find params[:id]
#comment = #post.comments.new
end
#posts/show.html.erb
<%- form_for [#post, #comment] do |f|-%>
<%= f.text_area :body -%>
<%= f.submit -%>
<%- end -%>
#comments_controller
def create
#post = #post.find params[:post_id]
#comment = #post.comments.new params[:comment]
if #comment.save
redirect_to #post
This is an old question, but I want to throw in my solution as well as the gem's README is still unhelpful after all these years. It builds upon #Kunday's answer. The following will be a tutorial to use the act_as_commentable gem to...
Allow users to create comments under each post.
Show all comments belonging to a post.
This assumes that you already have a working "blog", whether it be pictures or posts. Install gem, then run rails g comment to get started.
Allow users to create comments under each post.
First, inside the model that you want to use commentable gem, add the following line as suggested in the gem's README.
class Post < ActiveRecord::Base
acts_as_commentable
end
Then create a new comment controller with the create action. Please note that the :authenticate_user! is part of devise which is a gem for creating easy authentication. current_user is also part of devise as a helper. It is needed if you want to display the user's name/email under the comment body.
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
post = Post.find_by(id: params[:id])
comment = post.comments.build(comment_params)
comment.user = current_user
if comment.save
flash[:notice] = "Comment has been created."
redirect_to post
else
flash[:alert] = "Comment has not been created."
end
end
private
def comment_params
params.permit(:comment)
end
end
Next, set up the routes. It's just this. This means that when someone sends a post request to comments, we will run to create action inside the comments controller.
post 'comments' => 'comments#create', as: "create_comment"
The as: "create_comment" gives it an alias, so you can do create_comment_path. Now, on the show view of Post, we'll add the form. The divs will help you add css.
<div class="comment-section">
<%= form_tag create_comment_path, method: "post" do %>
<%= hidden_field_tag "id", #post.id %>
<%= text_area_tag :comment %>
<%= submit_tag "Submit" %>
<% end %>
</div>
Now to show each comment under the Post show view.
The divs will help you add css, comment.user.name will work if your User class has a name column. Else, change it to email or whatever identifier you choose to use.
<div class="comment_list">
<% #comments.each do |comment| %>
<%= comment.comment %> <br>
<%= comment.user.name %> <br>
<br>
<% end %>
</div>
And finally, in order for #comments to exist in the show page, go to your Post controller, and under show, add the following:
def show
#post = Post.find_by(id: params[:id])
#comments = #post.comments.all
end
This should be good for the requirements. Good luck.