Rails way to set up relationship for this model - ruby-on-rails

Being new at Ruby and Rails, I wasn't sure how to explain this in my title so i will do it here. My goal is to create many Products and with those have only one overall Location per submit.
I have a Product MVC and a quick ugly sketch of the form would be something like this:
Overall Location
form_for #product
<p>
<%= f.label :location %>:<br>
<%= f.text_field :location %>
</p>
Product one
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
Product Two (same)
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
Product Three(same)
<p>
<%= f.label :name %>:<br>
<%= f.text_field :name %>
<%= f.label :price %>:<br>
<%= f.text_field :price %>
</p>
<%= f.submit %>
<% end %>
How would you set it up so this relationship could take place so when a user creates 3 products on a form, he has only one location for all 3 of them?

This way:
class Location < AR::Base
has_many :products
end
class Product < AR::Base
belongs_to :location
end
You'd then set up a nested resource route:
resources :locations do
resources :products
end
And when you're adding a location, you can add products to it with fields_for.

is it required to use nested_attributes_for in this scenario..

Related

Triple nested model not building correctly

I have an Organisme that has many Servicepoints and each Servicepoint has many Addresses. The Servicepoint is set to accepts_nested_attributes_for :addresses so that I can create a service point and at the same time create an Address with it.
My problem is that that, I can't figure out how to create the address that will be linked to the Servicepoint and that Servicepoint be linked to the Organisme. I am creating the Servicepoint inside the show view of an Organisme.
View:
<%= form_for([#organisme, #organisme.servicepoints.build]) do |f| %>
<p>
<%= f.label :nom %><br>
<%= f.text_field :nom %>
</p>
<p>
<%= f.label :fax %><br>
<%= f.text_field :fax %>
</p>
<p>
<%= f.label :courriel %><br>
<%= f.email_field :courriel %>
</p>
<p>
<%= f.label :telephone %><br>
<%= f.text_field :telephone %>
</p>
<%= f.fields_for :addresses do |address_attributes| %>
<p>
<%= address_attributes.label :no_civique %><br>
<%= address_attributes.text_field :no_civique %><br>
<%= address_attributes.label :rue %><br>
<%= address_attributes.text_field :rue %><br>
<%= address_attributes.label :ville %><br>
<%= address_attributes.text_field :ville %><br>
<%= address_attributes.label :province %><br>
<%= address_attributes.text_field :province %><br>
<%= address_attributes.label :etat %><br>
<%= address_attributes.text_field :etat %><br>
<%= address_attributes.label :code_postal %><br>
<%= address_attributes.text_field :code_postal %><br>
</p>
<% end %>
<p>
<%= f.submit :Ajouter, class: 'btn btn-info' %>
</p>
<% end %>
Controller:
organisme/show
def show
#organisme = Organisme.find(params[:id])
end
servicepoint/create
def create
#organisme = Organisme.find(params[:organisme_id])
#servicepoint = #organisme.servicepoints.create(servicepoint_params)
redirect_to organisme_path(#organisme)
end
private
def servicepoint_params
params.require(:servicepoint).permit(:nom, :fax, :courriel, :telephone, addresses_attributes: [:id, :no_civique, :rue, :ville, :province, :etat, :code_postal])
end
Routes:
resources :organismes do
member { patch :activate }
member { patch :deactivate }
resources :addresses
resources :servicepoints do
resources :addresses
end
end
My problem right now is that the Address input information isn't even showing. I tried having a #servicepoint variable and then creating everything with that but the problem with that was that I could not link it to the Organisme.
If you need any more information I'll be happy to add anything.
Models:
class Organisme < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses
has_many :servicepoints
end
class Servicepoint < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses
belongs_to :organisme
end
class Address < ApplicationRecord
belongs_to :organismereferent, optional: true
belongs_to :organisme, optional: true
belongs_to :servicepoint, optional: true
end
I would build everything in the controller action:
<%= form_for([#organisme, #servicepoint]) do |f| %>
...
def show
#organisme = Organisme.find(params[:organisme_id])
#servicepoint = #organisme.servicepoints.build
#servicepoint.addressess.build
end
In the form you build a servicepoint, so an empty serviceform is shown as an empty form. No adress are shown because there is no address to iterate on. You need to build addresses too.
Be aware that your form will never allow you to edit servicepoint(s), because of the build in the form itself. And to allow the form to show more than one servicepoint, you need to iterate servicepoints somewhere.

Rails Nested Form - Unpermitted Parameters

I have an Orders model that has many Items and Customers. For some reason, and I have looked high and low for a solution, I am unable to save the attributes for Items and Customers in their respected tables when using a nested form.
I'm relatively new to Rails, so my apologies if I've missed something obvious.
Started POST "/orders" for ::1 at 2017-05-16 16:12:17 -0600 Processing
by OrdersController#create as HTML Parameters: {"utf8"=>"✓",
"authenticity_token"=>"k1QPQ560j44Mx0SNeCMBQAUGLQfEi4g0QpDfHuYeP4Zd7nVgcHJf3qXNsVQv29dV+5G0oJ7wiaoQ3Idw+DP+iw==",
"order"=>{"customer"=>{"name"=>"Test", "email"=>"Test",
"phone"=>"Test"}, "item"=>{"name"=>"Test", "ref_num"=>"Test",
"retail"=>"122"}, "status"=>"Test", "arrival"=>"06/06/19",
"tracking"=>"Test439"}, "commit"=>"Save Order"} Unpermitted
parameters: customer, item
Orders Controller
def create
#order = Order.new(order_params)
#order.items.build
#order.customers.build
#order.save
redirect_to #order
end
private
def order_params
params.require(:order).permit(:status, :arrival, :tracking,
customers_attributes: [:name, :phone, :email],
items_attributes: [:name, :ref_num, :retail])
end
Orders Model
class Order < ApplicationRecord
has_many :items
has_many :customers
accepts_nested_attributes_for :items, :customers
end
Orders Form (New)
<%= form_for :order, url: orders_path do |f| %>
<%# customer parameters%>
<%= f.fields_for :customers do |cu| %>
<p>
<%= cu.label :customer_name %><br>
<%= cu.text_field :name %>
</p>
<p>
<%= cu.label :email %><br>
<%= cu.text_field :email %>
</p>
<p>
<%= cu.label :phone %><br>
<%= cu.text_field :phone %>
</p>
<% end %>
<%# Item parameters %>
<%= f.fields_for :items do |it| %>
<p>
<%= it.label :item_name %><br>
<%= it.text_field :name %>
</p>
<p>
<%= it.label :reference_number %><br>
<%= it.text_field :ref_num %>
</p>
<p>
<%= it.label :retail %><br>
<%= it.text_field :retail%>
</p>
<% end %>
<%# order parameters%>
<p>
<%= f.label :status %><br>
<%= f.text_field :status %>
</p>
<p>
<%= f.label :est_arrival %><br>
<%= f.text_field :arrival %>
</p>
<p>
<%= f.label :tracking %><br>
<%= f.text_field :tracking %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', orders_path %>
This is happening because form_for :order doesn't make reference to your model object, it makes a simple :order param, which doesn't takes into consideration your model's accepts_nested_attributes_for, thus not building f.fields_for :customers with _attributes suffix. You should instantiate a Order object for the expected behavior to happen in your form_for #object instead of just referencing a :object which renders only the name of the param.

How to call a method on an object in a nested form in Ruby on Rails 3?

I have these two models
class Invoice < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items
...
end
class Item < ActiveRecord::Base
belongs_to :invoice
def total
price * quantity
end
...
end
and this nested (!) form that posts to both models:
<h1>Add an Invoice</h1>
<%= form_for #invoice do |f| %>
<p>
<%= f.label :recipient %>
<%= f.text_field :recipient %> </p>
<p>
<%= f.label :date %>
<%= f.text_area :date %>
</p>
<h2>Items</h2>
<p>
<%= f.fields_for(:items) do |f| %>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.label :price %>
<%= f.text_field :price %>
<%= f.label :quantity %>
<%= f.text_field :quantity %>
<%= f.label :total %>
<%= f.total %><!-- this method call is not working! -->
<% end %>
</p>
<%= f.submit %>
<% end %>
How can I do calculations on my items within the form?
In my Items model I have this method:
def total
price * quantity
end
However, in the form I can't get it to work with f.total. I keep getting this error:
undefined method `total' for #<ActionView::Helpers::FormBuilder:0x10ec05558>
What am I missing here?
You are calling a method not on your model object, but on f, which is a form helper (ActionView::Helpers::FormBuilder). Error message gives a hint to this.
To call on the item, you need to replace
<%= f.total %>
with
<%= f.object.total %>

How to create only the field_for object in a nested form

I have a nested form where users can create any amount of products (<%= f.fields_for :products do |product| %>) and at the same time also create a location (nested_form_for #location) to put those products. But instead, what i want is users to select a location and only be allowed to create the products. I don't want to create the locations at all on this form. The form also should not give a location per product but only one location for all of them.
How would you make the form select a location and create products only ?
This form creates both the location and X amount of products:
<%= nested_form_for #location, :validate => true do |f| %>
# This will turn into selecting of predefined locations and not creating
# the location as you see below this line
<%= f.label :business_name, "Business Name" %><br />
<%= f.text_field :business_name %>
<%= f.label :address %><br />
<%= f.text_field :address %>
<%= f.label :phone_number, "Phone Number" %><br />
<%= f.text_field :phone_number %>
<%= f.label :website %><br />
<%= f.text_field :website %>
</div>
<%= f.fields_for :products do |product| %>
<%= product.label :name %>:<br>
<%= product.text_field :name %>
<%= product.label :price %>:<br>
<%= product.text_field :price %>
<%= product.link_to_remove "Remove" %> # Removes a product field
<% end %>
</div>
<p><%= f.link_to_add "Add Product", :products %></p> # Ajax add product field
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If I understand you correctly, you want users to choose from a list of locations, and then add products to that location. These locations are predefined somewhere (I'm getting in your db_seed) in your application. Assuming those two things, then the question to your answer is just have a normal form_for #product and inside your form you will have a select with the option objects being the location where they users can choose.
<%= form_for #product do |p| %>
<%= p.label :name %>:<br>
<%= p.text_field :name %>
<%= p.label :price %>:<br>
<%= p.text_field :price %>
<%= select :product, :location_id, Location.all.collect {|l| [ l.business_name, l.id ] } %>
<% end %>
and in your controller you can just get the location with params[:product][:location_id] to retrieve the location the user selected and do your normal database stuff. Hopefully that's clear enough for you.
If you want to create more than one product at a time, you need to use a form_tag and generate your own helpers to add/remove products. This is more difficult but creates a better user experience.

How to have predefined categories?

I want my users to be able to select from predefined values of categories. I took a look at other Stackoverflow questions but didn't get them fully. Here is my code right now....
I have my Categories model and Users create prices (which is another name for Items).
class Category < ActiveRecord::Base
has_many :prices
def name
"#{category}"
end
end
My prices belong to categories. note: The prices table has a category_id.
class Price < ActiveRecord::Base
attr_accessible :name, :date, :price
belongs_to :user
belongs_to :category
end
Here is how the form and view look as of now:
Form
<%= form_for(#price) do |f| %>
<div class="field">
<%= f.label :date %><br />
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :price %><br />
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.collection_select :category_id, Category.all, :id, :name, :prompt => true %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
View
<p><b>User:</b><%= #price.user_id %></p>
<p><b>Date:</b><%= #price.date %> </p>
<p><b>Name:</b><%= #price.price_name %></p>
<p><b>Price:</b><%= number_to_currency(#price.price) %></p>
<p><b>Category:</b><%= #price.category.name %></p>
How do i create the categories i want in the drop down menu?
Thank you I'm a very appreciative!
You probably want the collection_select form helper method: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select
It will look something like this:
<div class="category">
<%= f.label :category %><br />
<%= f.collection_select :category, Category.all, :id, :name %>
</div>
Then in the view:
<p><b>Category:</b><%= #price.category.name %></p>
This assumes that your categories table has a name field which stores the category names.
you can create your data in db/seeds.rb
rake db:seed to load them (Load the seed data from db/seeds.rb)
http://railscasts.com/episodes/179-seed-data for more details

Resources