I'm trying to build a form that allows a user to create a new Post, a Tag for that post, and a TagType for that tag, all with one submit button.
My models are set up as follows:
class Post < ActiveRecord::Base
belongs_to :user
has_many :post_tag_relationships, dependent: :destroy
has_many :tags, through: :post_tag_relationships
.
.
end
class Tag < ActiveRecord::Base
has_many :reverse_post_tag_relationships, class_name: "PostTagRelationship"
has_many :posts, through: :reverse_post_tag_relationships,
class_name: "PostTagRelationship"
belongs_to :tag_type
.
.
end
class TagType < ActiveRecord::Base
has_many :tags
.
.
end
In the page controller where the form is located, I have the methods defined as follows:
#post = current_user.posts.build
#tag = #post.tags.build
#tag_type = #tag.tag_type.build
My form displays just fine if I only include the post and tag methods, as in:
<%= form_for(#post) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new post..." %>
</div>
<%= fields_for(#tag) do |u| %>
<div class="field">
<%= u.text_area :name, placeholder: "Tag" %>
</div>
<% end %>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
But when I add fields_for(#tag_type), with:
<%= fields_for(#tag_type) do |y| %>
<div class="field">
<%= y.select :name %>
</div>
<% end %>
I get an undefined method 'model name' for NilClass:Class
I'm pretty new with Rails, and my guess is that it has something to do with the fact that a tag belongs_to tag_types (whereas a post has_many tags). If anyone knows a fix, it would be much appreciated. Thanks.
You can use rails nested attributes http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html or create a form object http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Related
I have a many to many relationship between DailyQuestionSets and Questions. I have a one to many relationship between Questions and Answers. What I am having trouble working out is how to build the right kind of nested form that could retrieve a set of Questions with a label showing the question text as well as a form field with the answer which would get posted to the Answer model.
Models:
class Question < ApplicationRecord
has_many :dailyquestions, foreign_key: 'dailyquestion_id'
has_many :dailyquestionsets, :through => :dailyquestions
end
class DailyQuestion < ApplicationRecord
belongs_to :daily_question_set
belongs_to :question
end
class DailyQuestionSet < ApplicationRecord
has_many :daily_questions, foreign_key: 'question_id'
has_many :questions, :through => :daily_questions, :source => :question
end
class Answer < ApplicationRecord
belongs_to :users
belongs_to :questions
belongs_to :dailyquestionset
end
View:
<p id="notice"><%= notice %></p>
<%= form_tag('/answers/answerquestions') do %>
<% #questions.each do |q| %>
<%= fields_for '#answers[]', Answer do |a| %>
<div class="field">
<%= q.label :content %><br>
<%= a.text_field :answer_text %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
Controller:
def answerquestions
#dailyquestionset = DailyQuestionSet.get_today_dailyquestionset
#questions = #dailyquestionset.questions
#answers = []
#questions.count.times do
#answers << Answer.new
end
The problem is that I'm not able to get a label value out of q (Question) in the view and this is no surprise as I have taken a wild guess as to how to construct this nested form syntax.
undefined method `label' for #<Question:0x00007f54383ce748>
Extracted source (around line #8):
<div class="field">
<%= q.label :content %><br>
<%= a.text_field :answer_text %>
</div>
Any ideas on how to handle the form correctly most appreciated :)
It seems you are trying to create a text field and a related label with text taken from the Questions's content property:
<div class="field">
<%= a.label :answer_text, q.content %><br>
<%= a.text_field :answer_text %>
</div>
i.e. label is a method on the FormBuilder and the desired text (here q.content) is passed as second argument. See documentation.
I have two models in my app: "WorkPost" and "Contacts".
WorkPost
class WorkPost < ActiveRecord::Base
has_one :contacts
end
Contacts
class Contacts < ActiveRecord::Base
belongs_to :work_post
end
In my controller's new method I do:
def new
#work_post = WorkPost.new
#work_post.contacts
end
And in view I create form:
<%= form_for(#work_post) do |f| %>
<div class="field">
<%= f.label 'Vacation' %><br>
<%= f.text_field :post_title, :placeholder => 'Vacation here' %>
</div>
<div class="field">
<%= f.label 'Vacation description' %><br>
<%= f.text_area :post_body, :placeholder => 'Vacation description here' %>
</div>
<% f.fields_for :contacts do |cf| %>
<div class="field">
<%= cf.label 'Email' %><br>
<%= cf.text_field :emails, :placeholder => 'Email here' %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Post vacation", :class => 'btn_act' %>
</div>
<% end %>
But it seems like line <% f.fields_for :contacts do |cf| %> doesn't work.
Everything is rendered fine but email field.What I am doing wrong?
The problem is with this line
<% f.fields_for :contacts do |cf| %>
which should be
<%= f.fields_for :contact do |cf| %>
Also, the class name for the model and the association name for has_one/belongs_to should be singular.
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact #should be singular
end
#contact.rb
class Contact < ActiveRecord::Base #should be singular
belongs_to :work_post
end
Also, notice the change :contacts to :contact, as it is a has_one association.
Update:
Also, try the below changes
Include accepts_nested_attributes_for :contact in work_post.rb model
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact
accepts_nested_attributes_for :contact
end
Change the new method to below
def new
#work_post = WorkPost.new
#work_post.build_contact
end
I'm trying to build a nested form for a survey and having problems with my params hash missing values from within the fields_for block.
I have the following models. The way the app works is that an admin creates a MiniPost and its MiniPostQuestions. Then a client creates a new MiniPostSurvey using one of the MiniPosts. The client then emails out SurveyInvites to users. When a user responds, a new SurveyResponse is created, along with a new QuestionAnswer for each MiniPostQuestion in the survey.
class MiniPost < ActiveRecord::Base
has_many :mini_post_questions
has_many :question_answers, through: :mini_post_questions
has_many :mini_post_surveys
belongs_to :employer
def questions
mini_post_questions
end
def surveys
mini_post_surveys
end
end
class MiniPostQuestion < ActiveRecord::Base
has_many :question_answers
belongs_to :mini_post
belongs_to :employer
def answers
question_answers
end
end
class MiniPostSurvey < ActiveRecord::Base
belongs_to :mini_post
belongs_to :employer
belongs_to :company
has_many :survey_invites
has_many :survey_responses, through: :survey_invites
def questions
mini_post.questions
end
end
class SurveyInvite < ActiveRecord::Base
belongs_to :mini_post_survey
has_many :survey_responses
def responses
survey_responses
end
end
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
has_many :mini_post_questions, through: :question_answers
end
class QuestionAnswer < ActiveRecord::Base
belongs_to :survey_response
belongs_to :mini_post_question
validates :answer, presence: true
end
Here is my response form.
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :mini_post_questions, question do |q| %>
<%= q.fields_for :question_answers, question.question_answers.build do |a| %>
<%= f.label question.question %>
<%= a.text_area :answer, class: 'form-control' %>
<%= a.hidden_field :survey_response_id, value: #survey.id %>
<% end %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
My form renders correctly, however when I submit it, my params hash looks like this:
{"utf8"=>"✓",
"authenticity_token"=>"p8Tky2So10TH4FUUvLKhIh7j2vjNN39b3HDsF0cYE14=",
"survey_response"=>{"mini_post_questions"=>{"question_answers"=>{"answer"=>"", "survey_response_id"=>"11"}}},
"commit"=>"Submit",
"key"=>"e4fab42244db2286d471082696",
"controller"=>"surveys",
"action"=>"create"}
I would expect a mini_post_question key for each question, but I'm not sure how to get to that point.
I think you are on the right track, but you need to have your models accept nested attributes for the objects that you want in your form.
So I think in your SurveyResponse model, you would have
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
accepts_nested_attributes_for :question_answers
has_many :mini_post_questions, through: :question_answers
end
Also, since it looks like you are not modifying the mini question here, I would say that you don't need to accept nested attributes for the questions, but just have a hidden field that assigns the mini_question_id to the question_answer
So your form should be something like this
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :question_answers, #survey.question_answers.build do |q| %>
<%= q.label question.question %>
<%= q.text_area :answer, class: 'form-control' %>
<%= q.hidden_field :mini_post_question_id, value: question.id %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
Since your form is accepting nested attributes for question_answers, you won't need to supply the survey_id.
This should get you closer to what you would need in your form.
I am new to ruby and I am trying to put together a form that will allow you to add items to an order. The form will need to take a quantity for each item in the order.
class Order < ActiveRecord::Base
belongs_to :restaurant
has_many :selections
has_many :items, :through =>:selections;
end
class Selection < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
class Item < ActiveRecord::Base
belongs_to :menu
has_many :selections
has_many :orders, :through => :selections
end
class Restaurant < ActiveRecord::Base
has_many :orders
has_many :menus
has_many :items, :through => :menus
end
class Menu < ActiveRecord::Base
belongs_to :restaurant
has_many :items
end
order controller
# GET /orders/new
def new
#order = Order.new
#restaurant.items.all.each do |item|
#order.selections.build
end
end
orders/_form.html.erb :
The form is supposed to list out the available items and allow you to enter the quantity for an item.
<%= form_for [#restaurant,#order], :html => { :class => 'form-horizontal' } do |f| %>
<div class="control-group">
<%= f.label :current_table, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :current_table, :class => 'text_field' %>
</div>
</div>
<% f.fields_for :selections do |ff| %>
<div class="control-group">
<%= ff.label :quantity, :class => 'control-label' %>
<div class="controls">
<%= ff.text_field :quantity, :class => 'text_field' %>
</div>
</div>
<% end%>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
course_orders_path, :class => 'btn' %>
</div>
<% end %>
When I try to render the page I get the following error:
undefined method `quantity' for
<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Selection:0x007ffa0287cd60>
I realize this is probably because I haven't initialized any selections but I'm not entirely sure how/where I should do that. When the form is submitted I want to create an order with a selection for each of the non-empty quantities.
So my first question is how do I construct my form so that I can take a quantity for each item that I know about?
Do I need to initialize anything in the order controller to make this work?
Can you give me any advice or point me to a tutorial that shows me how to set up the create method of the order controller?
EDIT:
I added some code to the Order controller and the form, so when I render the page I no longer get an error, but none of my 'selection' fields rendered. I confirmed with some logging and the debugger that I correctly 'build' 4 selections so I would expect those form elements show up.
Any ideas would be appreciated.
Are you missing a
accepts_nested_attributes_for :nested_class
somewhere?
Also, I had to do something like
<%= form_for [#restaurant,#order] do |f| %>
...
<%= f.fields_for :selections, #order.selections do |ff| %>
...
<% end %>
...
<% end %>
I am using deeply nested model in my project (using simple_form and cocoon). Everything works fine as long as all nested objects are new.
My problem is, that I want to create a nested object from an existing (nested) object.
Here is my model
class Application < ActiveRecord::Base
belongs_to :submitter
has_one :composition
accepts_nested_attributes_for :submitter, :composition
end
class Submitter < ActiveRecord::Base
has_one :spouse
has_many :children
has_many :receipts
has_many :applications
accepts_nested_attributes_for :spouse, :children, :receipts, :applications
end
class Child < ActiveRecord::Base
belongs_to :submitter
has_many :receipts
end
The working process looks like this:
new Application --> new Submitter --> new Child
All can be created using one form.
Additionally, I also want to implement the following process:
new Application --> existing Submitter --> new Child
The existing object should be chosen by a dropdown list box.
Here is the (simplified, working) code of the view:
new.html.erb
<%= simple_form_for(#application) do |f| %>
<%= f.simple_fields_for :submitter do |submitter| %>
<%= render "submitter_fields", :f => submitter %>
<% end %>
<% end %>
_submitter_fields.html.erb
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= render "child", :f => f %>
_child.html.erb
<div id="childs">
<%= f.simple_fields_for :children do |child| %>
<%= render "child_fields", :f => child %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add child', f, :children %>
</div>
</div>
_child_fields.html.erb
<div class="nested-fields">
<%= f.input :firstname %>
<%= f.input :lastname %>
<%= link_to_remove_association "Remove child", f %>
</div>
Now I want to add a dropdown list which is populated with all existing Submitters. For example:
<%= f.assosciation :submitter %>
And here starts my problem: To build the form for adding a new child to the selected submitter, I need to assign this object to the form builder. I have no idea how to do this.
Can somebody give me a hint how to implement this? Or is this scenario simply not possible?
Thanks in advance!
Christian
simple_fields_for takes a second argument the object: https://github.com/plataformatec/simple_form/blob/master/lib/simple_form/action_view_extensions/form_helper.rb#L33 maybe if you pass your existing submitter it will work.