RubyOnRails - Creating new objects with relations - ruby-on-rails

i have 2 models, User and Technician
class User < ActiveRecord::Base
has_one :technician
end
class Technician < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
end
When creating a new Technician and trying to associate with an existing User it gives the error: User cannot be blank
the view of Technician.new (form) is:
<%= form_for(#technician) do |f| %>
<% if #technician.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#technician.errors.count, "error") %> prohibited this technician from being saved:</h2>
<ul>
<% #technician.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :codigo %><br>
<%= f.number_field :codigo %><br><br>
<%= f.label :user_id %><br>
<%= f.select :user_id, options_for_select(User.all.map{|u|[u.nome, u.id]}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
What am I doing wrong if, selecting an user from the select it won't associate it to the attribute user_id?
Thanks

Try using with collect like this
<%= f.select :user_id, User.all.collect {|u|[u.nome, u.id]}) %>
OR
If you are using Rails 4,you can use pluck
<%= f.select :user_id, User.pluck(:nome, :id))
For more details see this API
If that doesn't work,change your validation in Technician model like this
class Technician < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
Update
As you are using Rails4,you should be adding user_id to the permitted parameters like this
def your_params
params.require(:technician).permit(:user_id,:codigo)
end

Related

nested attributes + multi select: Couldn't find Collection with ID=["1", "2", "3"] for Product with ID=?

I have a many-many relationship with collections is a multi-select field for product
products_controller.rb
def new
#product = Product.new
#product.collections.build
#product.categories.build
#product
end
def create
#product = Product.new(product_params)
...
end
private
def product_params
params.require(:product).permit(:product_id, :name, :price, :popularity,
collections_attributes: [ id: [] ])
end
products model
class Product < ApplicationRecord
validates :product_id, uniqueness: true
has_and_belongs_to_many :collections, optional: true
accepts_nested_attributes_for :collections, reject_if: ->(attributes){ attributes['id'].blank? }, allow_destroy: true
end
products view
<%= form.fields_for :collections do |fc| %>
<%= fc.label :collections %>
<%= fc.select(:id, Collection.all.collect { |c| [c.name, c.id] },
{ include_blank: true, include_hidden: false }, {multiple: true}) %>
<% end %>
View will look like this as user has the option to select multiple collections
However, when I post to /create, it says
Log for products_params.inspect
Not quite sure what's wrong with it. Is it because ids can't take an array? If that so what is a solution for it.
Any help would be appreciated. Thanks!
UPDATE
whole product form. Please ignore product_id as it's not a primary key.
<%= form_with(model: product, local: true) do |form| %>
<% if product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="actions">
<%= form.label :product_id %>
<%= form.text_field :product_id %>
<%= form.fields_for :collections do |fc| %>
<%= fc.label :collections %>
<%= fc.select(:id, Collection.all.collect { |c| [c.name, c.id] },
{ include_blank: true, include_hidden: false }, {multiple: true}) %>
<% end %>
<%= form.submit %>
</div>
<% end %>
You don't need nested attributes to just associate records. This is an extremely common misconception. In fact using accepts_nested_attributes_for :collections would cause you to alter the collections table instead of your products_collections join table!
Instead just use the collection_ids= setter created by has_and_belongs_to_many :collections.
class Product < ApplicationRecord
validates :product_id, uniqueness: true
# has_and_belongs_to_many is always optional...
has_and_belongs_to_many :collections
end
<%= form_with(model: product, local: true) do |form| %>
# ...
<div class="field">
<%= form.label :product_id %>
<%= form.text_field :product_id %>
</div>
<div class="field">
<%= f.label :collection_ids %>
<%= f.collection_select(:collection_ids, Collection.all, :id, :name, multiple: true) %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
def product_params
params.require(:product).permit(
:product_id, :name, :price, :popularity,
collection_ids: [] # allows an array of values
)
end
This will automatically add/delete join rows depending on the contents of the array.
accepts_nested_attributes_for is only necessary if you need to pass attributes for another model (or join model) in a single form submission. accepts_nested_attributes_for can't actually be used to manipulate join table rows for has_and_belongs_to_many assocatiation as there is no model to accept nested attributes for. You would need to use has_many through: instead.

How to change existing model attribute through association

I have two tables: invoices and Invoice_Line_Items , invoice has_many Invoice_Line_items. Invoice_Line_Items belongs_to Invoice. Invoice has its foreign key in Invoice_line_items. When I create a new invoice, I choose the different Invoice_line_items and then save. However when I go and check the Invoice_line_item its invoice_id: is nil. It does not update the invoice_id foreign key in each of the Invoice_line_item.
update
It is true I am saving the child item before the parent (invoice).
models
class Invoice < ActiveRecord::Base
belongs_to :client
has_many :proposal_line_items, dependent: :destroy
has_many :suppliers, :through => :proposal_line_items
end
class Proposal_Line_Item < ActiveRecord::Base
belongs_to :proposal
belongs_to :supplier
belongs_to :invoice
end
form_for Invoice
<%= form_for(#invoice) do |f| %>
<% if #invoice.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#invoice.errors.count, "error") %> prohibited this invoice from being saved:</h2>
<ul>
<% #invoice.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :fecha_de_expedicion %><br>
<%= f.datetime_select :fecha_de_expedicion %>
</div>
<div class="field">
<%= f.label :invoice_line_item %><br>
<%= collection_select( :invoice_line_item, :invoice_line_item_id, #invoice_line_items, :id, :supplier_id, {}, {:multiple => true}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
thank you

rails 4 nested form fields_for are not displayed

I just started learning Rails 4.2. The problem is that one field in the form is not being displayed.
I have restaurant, category and a dish. While creating a dish, the category and restaurant will also be inputted via /dishes/new.
Expected behaviour: Dish, Category and Restaurant fields are displayed.
Actual behaviour: Only Dish and Category fields are displayed.
Here are my models
models/restaurant.rb
class Restaurant < ActiveRecord::Base
has_many :categories
has_many :dishes, :through => :categories
end
models/category.rb
class Category < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes
end
models/dish.rb
class Dish < ActiveRecord::Base
belongs_to :category
validates :name, :price, :category, :restaurant, :presence => true
accepts_nested_attributes_for :restaurant, :category
end
dish controller
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.build_category
restaurant = category.build_restaurant
end
def create
#dish = Dish.new(dish_params)
respond_to do |format|
if #dish.save
.... # default stuff #
end
end
end
# strong params
def dish_params
params.require(:dish).permit(:name, :description, :price, restaurant_attributes: [:name], category_attributes: [:name])
end
Dishes views/dishes/_form.html.erb
<%= form_for(#dish) do |f| %>
<% if #dish.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#dish.errors.count, "error") %> prohibited this dish from being saved:</h2>
<ul>
<% #dish.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :nameWoW %><br>
<%= f.text_area :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.number_field :price %>
</div>
*** The restaurant name field is not being displayed **
<%= f.fields_for :restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
<%= f.fields_for :category do |category| %>
<div class="field">
<%= category.label :Catname %><br>
<%= category.text_area :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I have followed steps from rails guide, browsed questions on stackoverflow and read some blog posts as well but havent been able to figure out whats wrong. Some micro level mistake is blocking me :( . Anyone knows whats wrong ?
Thanks in advance.
UPDATE:
Hey I found a solution.
def new
#dish = Dish.new
#dish.build_category
#dish.category.build_restaurant
end
This works well.But this is just a part of the actual solution. I had to do lot of /dish/create controller modification as well. I think the entire solution will have to be put in blog post. Otherwise it wont make any sense. I will soon be posting and updating it here.
You can add this in your dish.rb
class Dish
delegate :restaurant, to: :category
end
Or you can do
<%= f.fields_for :restaurant, #dish.category.restaurant do |restaurant| %>
<div class="field">
<%= restaurant.label :Restname %><br>
<%= restaurant.text_area :name %>
</div>
<% end %>
I think you are missing:
class Dish
belongs_to :restaurant, through: :category
end
You have it on the other side (many) but not there. You could test this by trying to output #dish.restaurant on your form (should be empty but not nil).
def new
# I think this is where
# I am making a mistake
#dish = Dish.new
category = #dish.category.build
restaurant = category.restuarant.build
end

How to include both dynamic select menu and nested attributes together in rails?

Consider i have three tables users, countries, states. I have a page to add a new user and when i add a new user i have to list the countries in the select box and on selecting the country the multiple select box should be loaded with the states of the country and i should be able to select the desired states.
Similarly i can click on the add button to add another select box and select another country and select states that belongs to that country and so on. And i know this needs nested attributes and dynamic select menu functionality but do not know how i can use these together.
The following are the ones that i tried
Models:
class Country < ActiveRecord::Base
has_many :states
attr_accessible :name
end
and
class User < ActiveRecord::Base
serialize :state_id
has_many :user_countries
accepts_nested_attributes_for :user_countries, :allow_destroy => true
has_many :state
attr_accessible :username, :user_countries_attributes
end
and
class State < ActiveRecord::Base
belongs_to :country
attr_accessible :name, :country_id
end
and
class UserCountry < ActiveRecord::Base
serialize :state_id
belongs_to :users
attr_accessible :country_id, :user_id, :state_id
end
Also the following image shows what i am trying to accomplish clearly
UPDATE
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username %>
</div>
<%= f.fields_for :user_countries do |country| %>
<%= render "user_country_fields", :f => country %>
<% end %>
<div class="add_variant"><%= link_to_add_fields "Add Country", f, :user_countries %></div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Update1:
<div class="entry_field">
<label>Country :</label>
<div id="field_country">
<%= f.collection_select :country_id, Country.all, :id, :name, :prompt => 'Select Country' %>
</div>
<div id="field_state">
<%= f.collection_select :state_id, State.all, :id, :name, {:prompt => 'Select State'}, { :multiple => true } %>
</div>
<%= link_to_remove_fields "remove", f %></div>
You can use nested_form (https://github.com/ryanb/nested_form) to achieve this in following way,
<%= nested_form_for(#user) do |f| %>
....
<%= f.fields_for :user_countries do |country| %>
<%= render "user_country_fields", :f => country %>
<% end %>
<div class="add_variant"><%= f.link_to_add "Add" :user_countries %></div>
<div class="actions">
<%= f.submit %>
</div>
Similarly, in partial
<%= f.link_to_remove "Remove" %>

Nested Attributes in Form Not showing

I have the 3 Models, that says a Voter has many votes and i'm trying to get the voter to vote on the same form as when the voting object is created but the field in my form isn't showing.
Here are my models:
class Voter < ActiveRecord::Base
attr_accessible :email_address, :verification_code, :verified, :votes_attributes
has_many :votes, :class_name => "Vote"
accepts_nested_attributes_for :votes
end
class Vote < ActiveRecord::Base
belongs_to :entry
belongs_to :voter
attr_accessible :entry, :voter, :voter_id
end
And in my form I have:
<%= form_for(#voter) do |f| %>
<% if #voter.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#voter.errors.count, "error") %> prohibited this voter from being saved:</h2>
<ul>
<% #voter.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email_address %><br />
<%= f.text_field :email_address %>
</div>
<div class="field">
<%= f.label :verification_code %><br />
<%= f.text_field :verification_code %>
</div>
<div class="field">
<%= f.label :verified %><br />
<%= f.check_box :verified %>
</div>
<div class="field">
<% f.fields_for :votes do |builder| %>
<fieldset>
<%= builder.label :votes, "Entry" %>
<%= collection_select(:entry, :entry_id, Entry.all, :id, :email_address, :prompt => 'Please select an Entry') %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
But the votes field isn't showing. And I can't understand why.
In rails 3 you need to use:
<%= f.fields_for :votes do |builder| %>
This will fix the problem.

Resources