Creating a form in the partials of a rendered collection - ruby-on-rails

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)

Related

Rails - submit and index on same page

I would like to know if there is any way that I can use my index page as submit page too.
for example i want be able to submit post and list already exists posts on same page.
Yes, you can display a form with form_for helper in your index view.
Your index action in posts_controller.rb should look like this:
def index
#post = Post.new
#posts = Posts.all
end
Your view/posts/index.html.erb view should look like this:
<%= form_for(#post) do |f| %>
<%= f.label :title, "Post title" %>
<%= f.text_field :title%>
<%= f.label :content, "Content" %>
<%= f.text_field :content%>
<%= f.submit "Add"%>
<% end %>
<%= render #posts %>
Then you have to create a partial called _post.html.erb in the view/posts folder in order to display the html for every single post.
Note that you still need a create action in your posts_controller, something like:
def create
#post = Post.new(post_params)
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:title, :content)
end
Let me know if it works :)
This is definitely wrong. Instead of routing all the POSTs and GETs to one method, you should read this:
Basically, you'll change your page to post data to a new method via ajax and replace the div element with a partial.

Rails 4 associate comment with blog

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.

Getting started with Rails tutorial 5.7 - Data not showing in view

I am trying out ruby on rails, going through the "Getting started with Ruby" tutorial. I have gone through steps to and including 5.7 and by now I should be able to create a new post and view it, the post is created, but the title and text is not showing.
The controller: posts_controller.rb
class PostsController < ApplicationController
def new
end
def create
#post = Post.new(params[post_params])
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
The view to create the post
<h1>New Post</h1>
<%= form_for :post, url: posts_path do |f| %>
  <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 show view for showing the post.
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
My guess is that the issue is with the passing of data to the database, but i can't figure out whats wrong. Any idea?
In the new controller action, be sure to assign a new instance of Post to an instance variable:
# app/controllers/posts_controller.rb
def new
#post = Post.new
end
Then, pass the #post instance variable to the form_for helper in the view:
# app/views/posts/new.html.erb
<%= form_for #post do |f| %>
The form_for helper expects a resource to be passed to it; the form is automatically submitted to the correct route based on the type of resource passed. You're passing a new resource in this instance, so the form is routed to the resource's create action.
I figured out that this line was the issue
#post = Post.new(params[post_params])
It should be
#post = Post.new(post_params)
Thanks to everybody who answered!
you may want to change the title of this post to something like "data not showing in view". here is what i would make sure of: that you have in fact created items in your database, i assume you are using sqlite. you can do this in the rails console. or you can enter directly into the form or "The view to create the post" as you call it.
it seems to me that your show action in your controller and your view are correct -- at least, they should show your data.
even without the form working, your data should still show up -- if you input your data via rails console.

What does the edit/update controller and form view look like for a nested form?

I think my view is being structured incorrectly, but it was the only way I could get all the form fields to appear.
I'm trying to make a for that has two nested models. I know best practice is to have only one nested model, so I can't seem to find the solution for this problem.
My #edit page is only passing a single parameter for the double nested field. As a result, the #update controller is not properly updating the model.
View
## edit.html.erb
<%= form_for :question, url: scenario_question_path(), method: :patch do |f| %>
{{ ...error & non-nested inputs }}
<ol>
<% #question.answers.each do |fa| %>
<%= f.fields_for :answers, fa do |ff| %>
<li>
<%= ff.text_field :answeroption %>
</li>
<% end %>
<% end %>
</ol>
{{ submit }}
Controller
## questions_controller.rb
def update
#scenario = Scenario.find(params[:scenario_id])
#question = #scenario.questions.find(params[:id])
if #question.update(params[:question].permit(:questionprompt, :text, answers: [:answeroption]))
redirect_to scenario_question_path
else
render 'edit'
end
end
def edit
#scenario = Scenario.find(params[:scenario_id])
#question = #scenario.questions.find(params[:id])
#questions = #scenario.questions.all
#answers = #question.answers.all
end
The params being passed when Edit is submitted. The problem is that "answers" actually had more than one changed fields, but only the first one appears.
{"utf 8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"nvydgO4oxCo58y4gmRAJ5P8Kc+kmbqWGoQ0IjIuzYiQ=",
"question"=>{"media"=>"test.jpg",
"questionprompt"=>"123123123",
"answers"=>{"answeroption"=>"2344634"}},
"commit"=>"Save Question",
"scenario_id"=>"1",
"id"=>"1"}
I outputted json and realized the model was structured in a different way than I realized. Also, the view was calling the same field 4 times, rather then calling four different fields.

multiple forms for different instances of the same object class on the same page in Rails

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.

Resources