I have a product table and a related product table, related works one way:
Product(id: int, name: string)
RelatedProduct(id: int, product1: int, product2: int)
With the following models:
class Product < ActiveRecord::Base
validates :name, :uniqueness => true, :presence => true
has_many :relations, :class_name => "RelatedProducts", :foreign_key => :product1, inverse_of: :source
has_many :related_products, through: :relations, :source => :destination
end
class RelatedProducts < ActiveRecord::Base
belongs_to :source, :class_name => "Product", inverse_of: :relations
belongs_to :destination, :foreign_key => :product2, :class_name => "Product"
end
This works if I prepopulate the RelatedProducts table, the show view will correctly display all the related products. What I cannot figure out is how do to populate RelatedProducts from the html?
<%= form_for(#product) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="related-products field">
<h3>Related Products</h3>
<%= f.collection_check_boxes :related_products, Product.where.not(id: #product.id), :self, :name %>
</div>
<div class="actions">
<%= f.submit 'Update Products' %>
</div>
<% end %>
The strong parameters are defined as:
params.require(:product).permit(:name, related_products: [:id, :name])
My solution was to make the view use the ids and then submit them
<div class="related-products field">
<h3>Related Products</h3>
<%= f.collection_check_boxes :related_products, Product.where.not(id: #product.id), :id, :name %>
</div>
I then coupled this with a function in the model to convert the id list to a list of products
def related_products_list=(ids)
self.related_products = ids.reject(&:empty?).collect { |id| Product.find(id) }
end
This worked for submitting but the checkboxes would not be pre checked on edits. This was because the model talks about products but the view has a list of ids so would not spot matches. The solution I used was to manually loop through the collection to create the checkboxes instead of using collection_check_boxes.
<% Product.where.not(id: #product.id).each do |p| %>
<%= check_box_tag 'product[related_products][]', p.id, #product.is_related_to?(p), id: "product_related_products_" + p.id.to_s %>
<%= label_tag "product_related_products_" + p.id.to_s, p.name %>
<% end %>
Related
I have three models in my rails 5 application... What I want to do is to be able to create a note on the person's "show" view, then the note should automatically link to that person and any other person I choose to attach the note to.
Here's where I got up to
Note
class Note < ApplicationRecord
has_many :person_notes
has_many :people, through: :person_notes
accepts_nested_attributes_for :person_notes
end
Person Note (Join table)
class PersonNote < ApplicationRecord
belongs_to :person
belongs_to :note
end
Person
class Person < ApplicationRecord
has_many :person_notes
has_many :notes, through: :person_notes
accepts_nested_attributes_for :person_notes
accepts_nested_attributes_for :notes
end
In my "show" section of my "people" controller I have the following:
def show
#notep = Note.new()
#person.notes << #notep
end
This is creating a join of a new note to my person record every time I open the page (obviously i only want the join to happen on the note I have created.)
I have rendered this in a modal as a partial in my "show" view (there is an "end" and a submit button but it's in between 3 divs and I know they weren't the cause of the issue so i didn't include them.:
<%= simple_form_for(#notep, remote: true) do |f| %>
<%= f.error_notification %>
<%= f.input :subject %>
<%= f.input :note %>
<%= f.input :date, html5: true %>
<div class="input-field">
<%= f.check_box :isalert, :id => "alert" %>
<%= f.label :isalert, :for => "alert" %>
</div>
<div class="input-field">
<%= f.check_box :archived, :id => "archived" %>
<%= f.label :archived, :for => "archived" %>
</div>
<div class="input-field">
<%= f.check_box :deleted, :id => "deleted" %>
<%= f.label :deleted, :for => "deleted" %>
</div>
<%= f.input :datecreated, html5: true %>
<%= f.input :user_id %>
<%= f.simple_fields_for :person_notes do |builder| %>
<%= builder.association :person, label_method: :lstfstfullname %>
<%= builder.input :deleted %>
<%= builder.input :datecreated, html5: true %>
<%= builder.input :user_id %>
<% end %>
You can probably tell I'm a total newb, but I'd appreciate any help I can get.
Thanks,
Leah
If I'm understanding this correctly, you'll want a separate Notes controller and create action to handle note creation. Then in your People show view, you can add a form and input field that submits to NotesController#create.
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 %>
Facing a issue in select tag with accepts_nested_attributes_for with has many and explicit foreign key. I am not able to get the associated values listed.
Models
class PlantPlate < Plate
has_many :unit_plates, :foreign_key => 'parent_id', :dependent => :destroy
accepts_nested_attributes_for :unit_plates, :allow_destroy => true
end
class UnitPlate < Plate
belongs_to :plant_plate, :foreign_key => 'parent_id'
end
View
/plant_plates/_form.html.erb
<%= nested_form_for([ :admin, #plant_plate ]) do |f| %>
<%= f.fields_for :unit_plates do |unit_plate| %>
<%= unit_plate.collection_select :parent_id, UnitPlate.all,:id,:name %>
<%end
<%end%>
I want to list all the associated unit plates in select tag . But somehow now able to do that with this select tag.
Thanks in advance
Try out form_for instead:
<%= form_for([:admin, #plant_plate]) do |f| %>
<%= f.fields_for :unit_plate do |unit_plate| %>
<%= unit_plate.collection_select :parent_id, UnitPlate.all, :id, :name %>
<% end %>
<% end %>
Try out using basic f.select:
<%= f.select :parent_id, options_from_collection_for_select(UnitPlate.all, 'id', 'name') %>
I'm new to rails and just cant get that problem solved.
i have 3 models. Orders, Products and LineItems.
I want to have a order form with checkboxes for each product. User selects appropriate products and submits the order.
I cannot get the form to create the correct hash.
class Order < ActiveRecord::Base
attr_accessible :account_id, :user_id
has_many :line_items, :dependent => :destroy
end
class LineItem < ActiveRecord::Base
attr_accessible :account_id, :product_id, :order_id
belongs_to :orders
belongs_to :product
end
Here the view:
<%= form_for 'line_items[]' do |f| %>
<%= f.select :account_id, options_from_collection_for_select( Account.all,
:id, :name ), :prompt => 'Select Account' %>
<% Product.all.each do |product| %>
<div>
<%= check_box_tag 'line_items[product_ids][]', product.id %>
</div>
<% end -%>
<div>
<%= f.submit 'save' %>
</div>
thanks!
You would need to use accepts_nested_attributes_for in your model to enable nested atributes from associated models. You may also want to check out this railscast and adapt to your needs.
For example in the orders model:
class Order < ActiveRecord::Base
attr_accessible :account_id, :user_id
has_many :products #This makes the association to products
has_many :line_items, :dependent => :destroy
accepts_nested_attributes_for :products #This allows the attributes from products accessible
end
Then the form could be:
<%= form_for #order do |f| %>
<%= f.select :account_id, options_from_collection_for_select( Account.all,
:id, :name ), :prompt => 'Select Account' %>
<%= f.fields_for :product do |product_form| %>
<%= product_form.check_box :id %>
<% end %>
<%= f.submit %>
<% end %>
i understand that if someone goes to an objects edit path, the form_for fields should populate. most of mines do except this one field, which has a has_many :through relationship with another table. how do you get it to pre populate with whatever the using typed in at creation?
for example...
<div class="lesson_content">
<%= f.label :content %>
<%= f.text_area :content %>
</div>
<div class="tags">
<%= f.label :tag_names, "Tags" %>
<%= f.text_field :tag_names, data: { autocomplete_source: tags_path} %>
</div>
my lesson content will populate correctly, but not my tags field. i have a lessons table, tags table, and an intervening tags_relationship table.
my lessons class is...
class Lesson < ActiveRecord::Base
attr_accessible :title, :desc, :content, :tag_names
belongs_to :user
has_many :tag_relationships, :autosave => true
has_many :tags, :through => :tag_relationships, :autosave => true
how do i get the tags field to populate? thanks
What you need is fields_for nested in your form. Details are here http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Even better, check out this great screencast from Ryan Bates that he just released http://railscasts.com/episodes/196-nested-model-form-revised
What you need is call accepts_nested_attributes_for from your Lesson class:
# app/models/lesson.rb
class Lesson < ActiveRecord::Base
attr_accessible :title, :desc, :content, :tag_names
belongs_to :user
has_many :tag_relationships, :autosave => true
has_many :tags, :through => :tag_relationships, :autosave => true
accepts_nested_attributes_for :tags
end
And then, in your controller/view:
# app/controllers/lessons_controller.rb
class LessonsController < ActiveSupport::Controller
def edit
#lesson = Lesson.find(params[:id])
end
end
<%= form_for(#lesson) do |f| %>
<div class="lesson_content">
<%= f.label :content %>
<%= f.text_area :content %>
</div>
<div class="tags">
<%- #lesson.tags.each do |tag| -%>
<%= fields_for(tag) do |t| %>
<%= t.label :name, "Tag" %>
<%= t.text_field :name, data: { autocomplete_source: tags_path} %>
<%- end -%>
<%- end -%>
</div>
<%- end -%>
However, this would show a text field for every tag. If you want to use a single text field for all the tags (separated by commas, for example), and also retrieve lessons filtering by tags, you should check this gem: acts-as-taggable-on.