How to access doubly nested models in rails? - ruby-on-rails

I have a route that looks like this
resources :questions do
resources :answers do
resources :comments
end
end
However, when I try to build a comment
<%= form_for([#answer, #answer.comments.build]) do |f| %>
<p>
<%= f.label :comment %>
<%= f.text_area :comment, :cols => "50", :rows => "30"%>
</p>
<p>
I get undefined method comments. This is what my create comment looks like
def create
#answer = Answer.find(params[:answer_id])
#comment = #answer.comments.create(params[:comment])
redirect_to question_path(#question)
end
And answer has_many comments, and comments belongs to answer. Any ideas? Thanks!

You can access models from any controller in your app (just call Model.class_method)
Looking at your code, I'd recommend doing something like this:
#app/views/answers/show.html.erb
<% #answer.comments.each do |comment| %>
<%= comment.value %>
<% end %>
<%= form_for #new_comment do |f| %>
<%= f.text_area :comment, :cols => "50", :rows => "30"%>
<% end %>
#app/controllers/answers_controller.rb
def new
#answer = Answer.find(params[:id])
#new_comment = Comment.new
end
#app/controllers/comments_controller.rb
def create
#comment = Comment.new(comment_params)
#comment.save
end
private
def comment_params
params.require(:comment).permit(:your, :attributes, :here)
end

Related

form_for nested resources(post, comment)

I have one question about form_for with nested resources. I create something like blog, with posts,comments, comments on comments(like replies).And I have an issue. Then I try to make comment it: "Redirected to http://localhost:3000/
Filter chain halted as :get_parent rendered or redirected
Completed 302 Found"
new.html.erb for comments:
<div class= "container" %>
<%= form_for #comment do |f| %>
<%= f.input :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
</div>
My comments controller:
before_filter :get_parent
def new
#comment = #parent.comments.build
end
def create
#comment = #parent.comments.build(params[:comment])
#comment.user_id = current_user.id
if #comment.save
redirect_to posts_path(#comment.post), :notice => 'Thank you for your comment!'
else
render :new
end
end
private
def comment_params
params.require(:comment).permit(:body, :title, :user_id, :commentable_id, :commentable_type)
end
def get_parent
#parent = Post.find_by_id(params[:post_id]) if params[:post_id]
#parent = Comment.find_by_id(params[:comment_id]) if params[:comment_id]
redirect_to root_path unless defined?(#parent)
end
end
post model:
has_many :comments, as: :commentable
belongs_to :user
def post
commentable.is_a?(Post) ? commentable : commentable.post
end
comment model:
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, :as => :commentable
routes:
resources :posts do
resources :comments
end
resources :comments do
resources :comments
end
post_show.html.erb
<h1><%= #post.title %></h1>
<div class="body">
<%= #post.body %>
</div>
<h2>Comments</h2>
<p><%= link_to 'Add a Comment', new_post_comment_path(#post) %></p>
<ul class="comment_list">
<%= render :partial => 'comments/comment', :collection => #post.comments %>
</ul>
github repo with app: https://github.com/Dmitry96/dasasd
Your new form does not pass neither post_id nor comment_id parameter. It should be eather in the form action url or in the form body.
I can not see all the picture, but I think you have to add parent id to the form action url. It is /comments now, has no parent id parameter in it. It must be /posts/:post_id/comments or /comments/:comment_id/comments.
Change your form to:
<%= form_for [#parent, #comment] do |f| %>
<%= f.input :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>

Param from form not saved

I've the following view in RoR:
<%= form_tag(url_for :controller => 'posts', :action => 'create', method: "post") do %>
<label>Zawartość</label>
<%= text_area_tag(:content) %>
<br/>
<label>Użytkownik</label>
<%= collection_select(:user, :user_id, User.all, :id, :name ) %>
<br/>
<% end %>
And the action of controller:
def create
#post = Post.new
#post.content = params["content"]
#post.user_id = params["user[user_id]"];
#post.save!
end
Unfortunately, user_id is saved as null. What is strange, the html is generated properly:
<select name="user[user_id]" ... >...</select>
Why?
Fix your create action to:
def create
#post = Post.new
#post.content = params["content"]
#post.user_id = params["user"]["user_id"];
#post.save!
end
I suggest you read Accessing elements of nested hashes in ruby.
You should stick to convention:
#config/routes.rb
resources :posts
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new post_params
redirect_to #post if #post.save #-> needs "show" action which I can explain if required
end
private
def post_params
params.reqire(:post).permit(:content, :user_id)
end
end
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_area :content %>
<%= f.collection_select :user_id, User.all, :id, :name %>
<%= f.submit %>
<% end %>
This will allow you to access url.com/posts/new to create a new post

undefined method `article_path'

this error is occuring and i have no idea why, thanks,
undefined method `article_path' for #<#:0x000001029cb960>
edit.html.erb
<h1>Editing <%= #article.name %></h1>
<%= form_for(#article) do |f| %> <-- ????something here?
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
articles model
class MediaController < ApplicationController
def index
#articles = Articles.all
end
def show
#article = Articles.find(params[:id])
end
def edit
#article = Articles.find(params[:id])
end
def update
#article.find(params[:id])
article_params = params.require(:article).permit(:name, :description, :location)
#article.update(article_params)
redirect_to #article
end
end
routes.rb
resources :media
patch "events/:id" => "media#update", as: "update_medium"
Change your routes to
patch "articles/:id" => "media#update", as: "update_medium"
And model name to singular like :
#articles = Article.all

accepts_nested_attributes_for with hidden_field

Been searching stackoverflow for an answer to this one all day. I have a form to create a new topic. The first post should also be created with the topic. All is well except user_id is not being saved to the post.
Post Model
class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
end
Topic Model
class Topic < ActiveRecord::Base
belongs_to :forum
belongs_to :user
has_many :posts
accepts_nested_attributes_for :posts
end
Post Controller
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to topic_path(#post.topic_id)
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:content, :topic_id, :topic_name, :user_id)
end
end
Topic Controller
class TopicsController < ApplicationController
def new
#topic = Topic.new
#topic.posts.build
end
def create
#topic = Topic.new(topic_params)
if #topic.save
redirect_to #topic
else
render 'new'
end
end
private
def topic_params
params.require(:topic).permit(
:topic_name,
:forum_id,
:user_id,
posts_attributes: [:id, :content, :topic_id, :topic_name, :user_id ] )
end
end
new/topic View
<%= form_for(#topic) do |f| %>
<%= f.hidden_field :forum_id, :value => params[:forum_id] %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.label :topic_name %>
<%= f.text_field :topic_name %>
<%= f.fields_for :posts do |p| %>
<%= p.label :content %>
<%= p.text_area :content %>
<% end %>
<%= f.submit "Post Topic", class: "btn btn-large btn-success" %>
<% end %>
I am not entirely sure why the user_id is not being passed to the post. Hopefully someone smarter than me can help me learn what to do :)
UPDATE
I changed the strong params in my topics controller to this.
def topic_params
params.require(:topic).permit(
:topic_name,
:forum_id,
posts_attributes: [:content, :topic_id, :id, '_destroy' ] ).merge(:user_id => current_user.id, posts_attributes: [:user_id => current_user.id])
end
Now the user_id is working but none of the posts_attributes like :content are being saved. I'm having a lot of fun with this one..
Notice the form attributes that being generated in the browser, all the nested attributes for post have a prefix like topic[post_attributes], try change the form to:
<%= form_for(#topic) do |f| %>
<%= f.hidden_field :forum_id, :value => params[:forum_id] %>
<%= f.label :topic_name %>
<%= f.text_field :topic_name %>
<%= f.fields_for :posts do |p| %>
<%= p.hidden_field :user_id, :value => current_user.id %>
<%= p.label :content %>
<%= p.text_area :content %>
<% end %>
<%= f.submit "Post Topic", class: "btn btn-large btn-success" %>
<% end %>
Short answer, user_id is not in the posts_attributes since the only attributes there is content, which means that allowing other attributes like topic_id and topic_name is useless.
Now that we cleared that, you SHOULD NOT use a form input for the value of the creator of any model, because it's easy for anyone to tamper with the form and set the value to anything else, like other user's id. Alternatively, you should set the user_id value in the controller, in your case, the TopicsController. Here is the code:
def create
_params = topic_params.deep_merge(user: current_user, posts_attributes: {user: current_user})
#topic = Topic.new(_params)
if #topic.save
redirect_to #topic
else
render 'new'
end
end
and remove the user_id hidden field from the form.
UPDATE: Your last code update contains an error; it should be .merge(:user_id => current_user.id, posts_attributes: {:user_id => current_user.id}). You used a square brackets around :user_id => current_user.id instead of curly ones.

Rails Post comments nested within category

I have a rails blog where all posts are nested under categories and now I am adding comments with are nested under posts but the form is throwing undefined method `post_comments_path' error.
I think I need to make the #posts something like #categories.post but I am unsure.
Routes
resources :categories do
resources :posts, path: 'article' do
resources :comments, :only => [:create]
end
end
Controller
def create
#post = Post.find(params[:post_id])
#comment = #posts.comments.create!(params[:comment])
redirect_to #post
end
View
<%= simple_form_for [#post, Comment.new ], :remote => true do |f| %>
<%= f.input :name %>
<%= f.input :email %>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
I think you're forgetting categories. You need to either provide a category:
Controller
def new
...
#category = Category.find(params[:category_id])
...
end
def create
#post = Post.find(params[:post_id])
#comment = #posts.comments.create!(params[:comment])
redirect_to #post
end
View
<%= simple_form_for [#category, #post, Comment.new ], :url => category_post_comments_path, :remote => true do |f| %>
<%= f.input :name %>
<%= f.input :email %>
<%= f.input :comment %>
<%= f.button :submit %>
<% end %>
or remove categories from the routes like so:
Routes
resources :posts, path: 'article' do
resources :comments, :only => [:create]
end

Resources