I'm trying to make two forms for two different models in the same view.
I have a model named category and a model named post.
Im trying to make a form for categories in the same view i have a form for posts.
The form for posts works fine, but when i'm trying to add the form for categories i get this error:
undefined method `model_name' for Category::ActiveRecord_Relation:Class
category.rb - model
has_many :posts
post.rb - model
has_many :categories
posts_controller
def index
#posts = new.Post
#categories = new.Category
end
def create
#posts = Post.create(post_params)
#posts.save
redirect_to :back
end
def create_cate
#categories = Categroy.create(categories_params)
#categroies.save
redirect_to :back
end
posts view - index.html.erb
<%= form_for(#posts) do |f| %>
<%= f.text_field :title %>
<%= f.text_area :content %>
<%= f.submit %>
<% end %>
<%= form_for(#categories) do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
routes.rb
resources :posts
resources :categories
root 'posts#index'
I have tried to search after if, but i can only find solutions for two models, one form.
Thanks in advance. :-)
Since you say its in the index action:
def index
#post = Post.new
#category = Category.new
end
In your view:
<%= form_for(#post) do |f| %>
<%= f.text_field :title %>
<%= f.text_area :content %>
<%= f.submit %>
<% end %>
<%= form_for(#category) do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Related
I have a simple blog app that has articles. Each article has comments. I'm trying to build nested comments using the closure_tree gem. I've been loosely following this sitepoint tutorial.
I have the following code:
models/article.rb
class Article < ActiveRecord::Base
has_many :comments
end
models/comment.rb
class Comment < ActiveRecord::Base
acts_as_tree order: 'created_at DESC'
end
routes.rb
resources :articles do
resources :comments
get 'comments/new/(:parent_id)', to: 'comments#new', as: :new_comment
end
views/articles/show.html.erb
<h1><%= #article.title %></h1><br>
<h3><%= #article.body %></h3>
Comments:
<% #article.comments.each do |comment| %>
Title: <%= comment.title %>, Body: <%= comment.body %>, User: <%= comment.user_id %>
<%= link_to 'reply', article_new_comment_path(parent_id: comment.id, article_id: #article.id) %>
<% end %>
</ul>
<!-- FORM FOR NEW COMMENT -->
<%= form_for ([#article, #article.comments.build]) do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
views/comments/new.html.erb
<%= render "form" %>
views/comments/_form/html.erb
<%= form_for ([#comment.article_id, #article]) do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.submit %>
<% end %>
controllers/comments_controller.rb
[...]
def new
#article = Article.find(params[:article_id])
#comment = Comment.new(parent_id: params[:parent_id])
end
def create
# binding.pry
if params[:comment][:parent_id].to_i > 0
parent = Comment.find_by_id(params[:comment].delete(:parent_id))
#comment = parent.children.build(comment_params)
else
#article = Article.find(params[:article_id])
#comment = #article.comments.create(comment_params)
[...]
end
When I click the link_to in articles/show.html.erb in order to reply to an existing comment, I hit the new action as expected and pass the comment's parent_id and article_id also as expected into params.
The problem arises when I leave the new action. I expect to hit the form partial and then go into the create action for a comment. Instead I'm somehow hitting the update action for an Article, even though I don't even have one in my ArticlesController. I'm quite a Rails noob and I think I'm messing up in my nested routes. Any help would be much appreciated.
I try to create an action 'subcomment' or 'child' in the controller. Something like this 'post article/:id/comments/:id/child'.
resources :articles do
resources :comments do
post :child
end
end
In action child something like this.
def child
#article = Article.find(params[:article_id]
#comment = #article.comments.find(params[:comment_id])
#child_comment = #comment.children.build(comment_params)
redirect_to article_path(#article)
end
The view is other problem. Iterate over then articles.comments and comments.children and create a form with the url child_article_comment_path(#article, #comment).
I want to create a form for "Comments" route which is a member of Article Resources:
resources :articles do
member do
post 'comments'
end
end
I want the comment form to be in Articles#Show page. The problem i got an error:
First argument in form cannot contain nil or be empty
If the for is like this:
<div>
<%= form_for #comm do |c| %>
<%= c.label :Your_comment %>
<%= c.text_area :commBody %>
<%= c.submit 'submit' %>
<% end %>
</div>
So how to do it ?
If this is your controller,
def show
#article = Article.find(params[:id])
end
and you want to create a form for a new Comment related to #article that points to POST /articles/3/comments:
<%= form_for([#article, Comment.new], as: :article, url: comments_article_path(#article)) do |f| %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit 'Submit' %>
<% end %>
Don't forget to add accepts_nested_attributes_for :comments in the Article model. And also don't forget to setup the whitelisted params in the ArticleController.
Another thing: don't use abbreviations for your variable names. Use #article and #comment, not #art and #comm.
#config/routes.rb
resources :articles do
post :comment, on: :member #-> url.com/articles/:id/comment
end
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def show
#article = Article.find params[:id]
#comment = #article.comments.new
end
end
#app/views/articles/show.html.erb
Comment:
<%= form_for [#article, #comment], url: article_comment_path(#article) do |c| %>
<%= c.label "Your Comment" %>
<%= c.text_area :commBody %>
<%= c.submit %>
<% end %>
I have an event model and a Q+A model inside the event.
I'm new to rails so not sure if there is an alternate way to do this
Right now, inside an event show.html.erb, I have both a form to post a question, and each question will have a form to post an answer
The routes sit like this right now
resources :events do
resources :event_questions, only: [:create, :destroy]
end
When you create a question inside my show.html.erb, it's being routed through EventQuestionsController and I access the event_id via params. Do I have to do it the same way with my event_answer?
And by that I mean, do I have to nest event_answers inside event_questions. I will need to know the event_id and the event_question_id.
If that's the only way to access the params. Would it look like this?
resources :events do
resources :event_questions, only: [:create, :destroy] do
resources :event_answers, only: [:create, :destroy]
end
end
event_questions_controller.rb
def create
#event_question = EventQuestion.new(event_question_params)
if #event_question.save
event = Event.find(params[:event_id])
#event_question.event = event
redirect_to event
else
redirect_to :back
end
end
show.html.erb
<%= form_for(#event_question, :url => event_event_questions_path(#event)) do |f| %>
# form stuff
<% end %>
I started changing my answer form to this
<%= #event.event_questions.each do |q| %>
<%= q.question %>
<%= q.fields_for :answers do |a| %>
<%= a.label :answer %>
<%= a.text_field :answer %>
<%= a.submit "Answer" %>
<% end %>
<% end %>
You shouldn't need to directly access the params to create your nested records. For example, if in your event#new action, you may have something like
#event = Event.new
3.times do
question = #event.questions.build
5.times do
question.answers.build
end
end
This will create a new Event and take you to the New page. Within your New page, you should have nested fields to create and update the nested models.
In the form, you can use fields_for to access the associated model's records to that event record. In the new action case, we are building 3 questions and each question has 5 answers.
<%= simple_form_for #event do |f| %>
<%= f.input :attribute1 %>
<%= f.input :attribute2 %>
<%= f.fields_for :questions do |builder| %>
<%= render 'questions', f: builder %>
<% end%>
<% end %>
I generally like to use a partial when doing nested associations, but if you wanted to keep it all in one file (see below), it would looks something like this.
<%= simple_form_for #event do |f| %>
<%= f.input :attribute1 %>
<%= f.input :attribute2 %>
<%= f.fields_for :questions do |q| %>
<%= q.input :question_text %>
<%= q.fields_for :answers do |a| %>
<%= a.input :answer_text %>
<% end %>
<% end%>
<% end %>
In your show action, you may have something like this
#event = Event.find(params[:id])
#questions = #event.questions
#answers = #question.answers if #questions
From here, you have three instance variables assigned and able to access the associated records to your events and questions.
With some help I derived this answer from a bit of kobaltz answer and some other help.
The alternate method would be putting the information in hidden fields and passing it to the controller
<%= #event.event_questions.each do |q| %>
<%= q.question %><br>
<% q.event_answers.each do |a| %>
<%= a.answer %>
<% end %>
<%= form_for(EventAnswer.new) do |f| %>
<%= hidden_field_tag :event_question_id, q.id %>
<%= hidden_field_tag :event_id, #event.id %>
<%= f.label :answer %>
<%= f.text_field :answer %>
<%= f.submit "Answer" %>
<% end %>
<% end %>
i have some problems with my app, i have posts, posts has_many responces
when i create new responce to the post, not added in the db 'responce' post_id
my routes.rb
resources :categories do
resources :posts
end
resources :posts do
resources :responces
end
controller
class ResponcesController < ApplicationController
def new
#post = Post.find(params[:post_id])
#responce = #post.responces.new(post_id:params[:post_id])
end
def create
#responce = current_user.responces.build(responce_params)
#post = Post.find(params[:post_id])
if #responce.save
flash[:success] = "Вы откликнулись на задание"
redirect_to post_path #post
else
render 'new'
end
end
def show
end
private
def responce_params
params.require(:responce).permit(:price, :comment, :post_id)
end
end
view
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
but if add to the view this
<%= f.collection_select :post_id, Post.all, :id, :name %>
rails create post_id to the db
help
You are doing several things the wrong way.
First: I don't think you need two separate resources for the same model. I'd recomend nesting all three resources upon each other like this.
resource :categories do
resource :posts do
resource :responces
end
end
This way you'll be able to find the needed category_id and post_id in the params hash.
I'd also recomend adding :shalow => true to the :categories resource to make your routes a bit prettier.
Second: you need to assign the params[:post_id] in your create action, like this.
#responce = current_user.responces.build(responce_params)
#responce.post_id = params[:post_id]
#post = #responce.post
Alternatevely you can just add a hidden field to your form like I show below, but it I don't like that approach, 'cause it can lead to security risks.
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.hidden_field :post_id, :value => #post.id %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
In your form you aren't passing in the post_id. You probably want something like this:
<%= form_for([#post, #responce]) do |f| %>
<%= f.text_area :price %>
<%= f.hidden_field :post_id, :value => #post.id %>
<%= f.submit "GO", class: "btn btn-large btn-primary" %>
<% end %>
The hidden field will pass the id of the current post into your form as the post_id parameter.
I'm working to install the acts_as_commentable plugin on my
Rails 3 app.
After adding "acts_as_commentable" to my book model, I then added a
comment form on my book show view:
<% form_for(#comment) do|f| %>
<%= f.hidden_field :book_id %>
<%= f.label :comment %><br />
<%= f.text_area :comment %>
<%= f.submit "Post Comment" %>
<% end %>
Then in the controller (comments_controller.rb),
def create
#comment = Comment.new(params[:comment])
Book.comments.create(:title => "First comment.", :comment => "This
is the first comment.")
end
Then when submitting a comment, it returns the error: "unknown
attribute: book_id"
From the log:
Processing by CommentsController#create as HTML
Parameters: {"comment"=>{"comment"=>"WOOOW", "book_id"=>"32"},
"commit"=>"Post Comment",
"authenticity_token"=>"5YbtEMpoQL1e9coAIJBOm0WD55vB2XRZMJa4MMAR1YI=",
"utf8"=>"✓"}
Completed in 11ms
ActiveRecord::UnknownAttributeError (unknown attribute: book_id):
app/controllers/comments_controller.rb:3:in `new'
app/controllers/comments_controller.rb:3:in `create'
Suggestions?
<%= f.hidden_field :book_id %>
It means your Comment model has no book_id field.
Also, it's not a very good idea to call a field as the model name (comment). Use body (or message) instead of comment for the field which should contains the message body.
I think you have to options:
Option 1)
The view:
<% form_for(#comment) do|f| %>
<%= f.hidden_field :commentable_id, :value => #book.id %>
<%= f.hidden_field :commentable_type, :value => 'Book' %>
<%= f.label :comment %><br />
<%= f.text_area :comment %>
<%= f.submit "Post Comment" %>
<% end %>
The controller:
def create
#comment = Comment.create(params[:comment])
end
Option 2)
In the controller:
def create
#book = Book.find(params[:comment][:book_id])
#comment = #book.comments.create(params[:comment].except([:comment][:book_id]))
end
I haven't tested the code, but the idea should be correct
Update, given you want to comment on various models (i'm writting my code without testing it...). So let's say you have Book and Magazine, and you want to comment on them. I guess I would define nested routes for them.
map.resources :books, :has_many => :comments
map.resources :magazines, :has_many => :comments
And then in your controller you could do:
before_filter :find_commentable
def find_commentable
#commentable = Book.find(params[:book_id]) if params[:book_id]
#commentable = Magazine.find(params[:magazine_id]) if params[:magazine_id]
end
And in the new view:
<% form_for :comment, [#commentable, #comment] do |f| %>
<%= f.label :comment %>
<%= f.text_area :comment %>
<%= f.submit %>
<% end %>
So the create action could look something like:
def create
#user.comments.create(params[:comment].merge(:commentable_id => #commentable.id, :commentable_type => #commentable.class.name))
redirect_to #commentable
end
Maybe there are even better ways to do it...