Rails4 - Displaying items in the orders form - ruby-on-rails

I want the user to search through existing items from the items table in the orders form, it works for clients but not for items, it gives an error: Association :item not found
Models
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :client
has_many :order_items
has_many :items, :through => :order_items
end
class Item < ActiveRecord::Base
has_many :order_items
has_many :orders, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
Migration
class CreateOrderItems < ActiveRecord::Migration
def change
create_table :order_items do |t|
t.integer :item_id
t.integer :order_id
t.timestamps
end
add_index :order_items, [:item_id, :order_id]
end
end
View
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<%= f.association :client, collection: Client.all, label_method: :name, value_method: :id, prompt: "Choose a Client", input_html: { id: 'client-select2' } %>
<%= f.association :item, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'client-select2' } %>
<%= f.input :memo, label: 'Comments' %>
<%= f.submit %>
<% end %>
Controller
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
end
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, items_attributes: [:id, :name, :price, :quantity, :status, :_destroy])
end
Answer
In the form use instead:
using rails-select2 gem
<%= f.association :items, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'item-select2' } %>
or without select2
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
Thanks to JKen13579

The reason that you're receiving the error for item but not for client is because there is one client associated to an order, but more than one item associated to an order. It's saying :item not found because you should be using :items (note the plural).
To allow multi-select for your order's items, replace your f.association item line with:
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
And then in your controller, be sure to permit item_ids. In addition, you don't need item_attributes, because you're not using accepted_nested_attributes_for :items.
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, item_ids: [])
end
See this SO answer for more information about has_many :through multi-select.

Related

Rails nested attributes "no implicit conversion of Symbol into Integer" for has_many association

I've following are the Model codes.
user.rb
has_many :teams, dependent: :destroy
has_many :companies, dependent: :destroy
after_create :create_tables!
def create_tables!
companies.create!
Team.create!(user_id: self.id, company_id: Company.where(user_id: self.id).first.id)
end
company.rb
belongs_to :user
has_many :teams, inverse_of: :company, dependent: :destroy
has_many :users, through: :teams
accepts_nested_attributes_for :teams
team.rb
belongs_to :user
belongs_to :company, inverse_of: :teams
Following are my Controller codes
companies_controller.rb
def new
#company = current_user.companies.new
#company.build_teams
end
def update
current_user.companies.first.update_attributes(company_params)
respond_to {|format| format.js}
end
private
def company_params
params.require(:company).permit(:name, :about, :problem, :solution, :logo, :url, :email, :phone, :category, :started_in,
teams_attributes: [:position, :admin])
end
In views
<%= form_with model: #company, method: :put do |f| %>
<%= f.fields_for :teams_attributes, #company.teams.first do |team| %>
<%= team.hidden_field :admin, value: true %>
<%= team.text_field :position, placeholder: 'Eg: CEO', class: 'input' %>
<% end %>
<%= f.submit 'Next' %>
<% end %>
When i try this in rails console it works and saved in db, in views params are also passing good. Its below
But in views it says
TypeError in CompaniesController#update no implicit conversion of Symbol into Integer
It should be f.fields_for :teams instead of f.fields_for :teams_attributes
<%= form_with model: #company, method: :put do |f| %>
<%= f.fields_for :teams, #company.teams.first do |team| %>
<%= team.hidden_field :admin, value: true %>
<%= team.text_field :position, placeholder: 'Eg: CEO', class: 'input' %>
<% end %>
<%= f.submit 'Next' %>
<% end %>

Ruby on Rails | one form - three tables (can't save the form content)

I am trying to write an app - simple form for user's details which saves data to three different tables (1.users, 2.companies, 3.adresses).
I have set some assosiations using belongs_to and has_many, and also use nested_attributes and fields_for to build one form. But I can't save data.
I am a newbie, so probably I'm making some stupid mistakes, but I cannot really find them since 3 days. Also tried to look in google and here, among forum posts, but didn't find a code, where the problem was connected with child class. My assosiations between user, company and adress are quite weird. Can anyone help me?
Here is my form:
<%= simple_form_for #user do |f| %>
<h5>Personal Details</h5>
<%= f.input :firstname, label: 'Your First Name:' %>
<%= f.input :lastname, label: 'Your Last Name:' %>
<%= f.input :email, label: 'Your Email:' %>
<%= f.input :dateofbirth, label: 'Your Date of Birth:' %>
<%= f.input :phonenumber, label: 'Your Phone Number' %>
<h5>Adress</h5>
<%= f.fields_for :adresses do |g| %>
<%= g.input :street, label: 'Street:' %>
<%= g.input :city, label: 'City:' %>
<%= g.input :zipcode, label: 'Zip Code:' %>
<%= g.input :country, label: 'Country:' %>
<% end %>
<h5>Company</h5>
<%= f.fields_for :companies do |h| %>
<%= h.input :name, label: 'Name:' %>
<% end %>
<%= f.fields_for :adresses do |i| %>
<%= i.input :comstreet, label: 'Street:' %>
<%= i.input :comcity, label: 'City:' %>
<%= i.input :comzipcode, label: 'Zip Code:' %>
<%= i.input :comcountry, label: 'Country:' %>
<% end %>
<%= f.button :submit %>
<% end %>
user.rb
class User < ApplicationRecord
belongs_to :company, inverse_of: :users
belongs_to :adress, inverse_of: :users
validates_presence_of :firstname, :lastname, :email
validates_length_of :firstname, :maximum => 100
validates_length_of :lastname, :maximum => 100
end
company.rb
class Company < ApplicationRecord
has_many :users, inverse_of: :companies
belongs_to :adress, inverse_of: :companies
accepts_nested_attributes_for :users
end
adress.rb
class Adress < ApplicationRecord
has_many :users, inverse_of: :adresses
has_many :companies, inverse_of: :adresses
accepts_nested_attributes_for :users, :companies
end
users_controller
class UsersController < ApplicationController
def index
end
def new
#user = User.new
#company = Company.new
#adress = Adress.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to root_path
end
end
private
def user_params
params.require(:user).permit(:firstname, :lastname, :email, :dateofbirth,
:phonenumber, company_attributes: [:name],
adress_attributes: [:street,:city, :zipcode, :country, :comstreet,
:comctiy, :comzipcode, :comcountry] )
end
end
In your user.rb file:
class User < ApplicationRecord
belongs_to :company, inverse_of: :users
belongs_to :adress, inverse_of: :users
validates_presence_of :firstname, :lastname, :email
validates_length_of :firstname, :maximum => 100
validates_length_of :lastname, :maximum => 100
# add nested attributes here not in other models
accepts_nested_attributes_for :companies
accepts_nested_attributes_for :addresses
end
Also, in your controller: carefully check the names of parameters passed. address_attributes misspelled
def user_params
params.require(:user).permit(:firstname, :lastname, :email, :dateofbirth,
:phonenumber, company_attributes: [:name],
address_attributes: [:street,:city, :zipcode, :country, :comstreet,
:comctiy, :comzipcode, :comcountry] )
end
In the view, remove multiple form elements for address. You wrote twice.
I have made few changes in the code and able to save the form, please check
Here is my form:
<%= simple_form_for #user do |f| %>
<h5>Personal Details</h5>
<%= f.input :firstname, label: 'Your First Name:' %>
<%= f.input :lastname, label: 'Your Last Name:' %>
<%= f.input :email, label: 'Your Email:' %>
<%= f.input :dateofbirth, label: 'Your Date of Birth:' %>
<%= f.input :phonenumber, label: 'Your Phone Number' %>
<h5>Adress</h5>
<%= f.fields_for :adress_attributes do |g| %>
<%= g.input :street, label: 'Street:' %>
<%= g.input :city, label: 'City:' %>
<%= g.input :zipcode, label: 'Zip Code:' %>
<%= g.input :country, label: 'Country:' %>
<% end %>
<h5>Company</h5>
<%= f.fields_for :company_attributes do |h| %>
<%= h.input :name, label: 'Name:' %>
<%= h.fields_for :adress_attributes do |i| %>
<%= i.input :street, label: 'Street:' %>
<%= i.input :city, label: 'City:' %>
<%= i.input :zipcode, label: 'Zip Code:' %>
<%= i.input :country, label: 'Country:' %>
<% end %>
<% end %>
<%= f.button :submit %>
<% end %>
user.rb
class User < ApplicationRecord
belongs_to :company, inverse_of: :users
belongs_to :adress, inverse_of: :users
validates_presence_of :firstname, :lastname, :email
validates_length_of :firstname, :maximum => 100
validates_length_of :lastname, :maximum => 100
accepts_nested_attributes_for :company
accepts_nested_attributes_for :address
end
company.rb
class Company < ApplicationRecord
has_many :users, inverse_of: :companies
belongs_to :adress, inverse_of: :companies
accepts_nested_attributes_for :users
accepts_nested_attributes_for :adress
end
adress.rb
class Adress < ApplicationRecord
has_many :users, inverse_of: :adresses
has_many :companies, inverse_of: :adresses
accepts_nested_attributes_for :users, :companies
end
users_controller
class UsersController < ApplicationController
def index
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to root_path
end
end
private
def user_params
params.require(:user).permit(:firstname, :lastname, :email, :dateofbirth,
:phonenumber, company_attributes: [:name, adress_attributes: [:street,
:ctiy, :zipcode, :country]],
adress_attributes: [:street,:city, :zipcode, :country] )
end
end
It is working now and able to save user, address and company with company address.

how to leave the field filled with fields_for?

I have a problem : when a customer enters his shipping and billing informations in my form, the fields of the address model lose all information if the page is reloaded.
It works with the other fields, like email, that are included directly in the order model. How could I leave the fields filled after reloading ?
Here's my new.html.erb file :
<%= form_for #order do |f| %>
<ul>
<% #order.errors.each_with_index do |msg, i| %>
<li><%= msg[1] %></li>
<% end %>
</ul>
<%= f.text_field :email, placeholder: "email" %>
<%= f.fields_for :shipping_address_attributes do |sa| %>
<%= sa.text_field :first_name, placeholder: "Firstname" %>
<%= sa.text_field :last_name, placeholder: "Name", autocomplete: true %>
<%= sa.text_field :address1, placeholder: "Address", autocomplete: true %>
#etc.
<% end %>
<p><%= f.submit 'Next step' %></p>
<% end %>
My models :
class Order < ActiveRecord::Base
belongs_to :billing_address, :class_name => "Address"
belongs_to :shipping_address, :class_name => "Address"
accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address, reject_if: :bill_to_shipping_address
class Address < ActiveRecord::Base
belongs_to :user
has_many :billing_addresses, :class_name => "Order", :foreign_key => "billing_address_id", dependent: :nullify
has_many :shipping_addresses, :class_name => "Order", :foreign_key => "shipping_address_id", dependent: :nullify
validates_presence_of :first_name, :last_name, :address1, :city, :country, :phone, :postal
and my order_controller.rb:
def new
#user = current_user
#order_items = current_order.order_items
#order = current_order
#amount = #order.subtotal
end
def update
#order_items = current_order.order_items
#order = current_order
if #order.update(order_params)
redirect_to recapitulatif_de_la_commande_path
else
redirect_to(:back)
end
end
EDIT
Maybe the error is due to the fact that the order is not linked to any shipping address before the update action ? It works only if address model validate the presence of each attributes.
Any idea ?

Add extra text/content to select menu

I am trying to create a drop-down-select menu that users can be selected from. I want to also have the number of projects they are assigned to displayed next to their name
class User < ActiveRecord::Base
attr_accessible :email, :username, :password, :password_confirmation, :remember_me, :first_name, :last_name
belongs_to :department
has_many :project_assignments
.
class ProjectAssignment < ActiveRecord::Base
attr_accessible :user_id, :project_id, :active, :notes
belongs_to :user, counter_cache: :projects_count
belongs_to :project
end
.
class Project < ActiveRecord::Base
attr_accessible :program_id, :title, :status, :topic_number, :award_number, :task_data_attributes, :user_ids, :technical_poc_id, :contacts_attributes, :project_fields_attributes, :division_id, :company_name
attr_accessor :old_project_id
belongs_to :program
belongs_to :division
belongs_to :company
has_many :users, through: :project_assignments
.
<div class="col-md-12">
<p>New Assignment</p>
<%= form_for #project.project_assignments.new, url: program_project_assignments_path(#program, #project), html: { id: 'staff-form' } do |f| %>
<%= f.select :user_id, options_from_collection_for_select(User.all, :id, :full_name), {}, class: 'form-control input-sm', placeholder: 'User' %>
<%= hidden_field_tag "project_id",nil,:value => #project.id %>
<%= f.submit 'Assign', class: 'btn-gray' %>
<% end %>
</div>
All the above code is just excerpts from their respective files. The above html works for populating the drop-down with names, but obviously no code there is attempting to add the number of assigned projects
Use options_for_select
<%= f.select :user_id, options_for_select(User.all.collect{|u|["#{u.full_name} #{u.project_assignments.count}", u.id]}), {}, class: 'form-control input-sm', placeholder: 'User' %>
It will be efficient to load the users and eager load project assignment in your controller
#users = User.includes(:project_assignment).all

Access parent attribute in independent nested model view

I have nested resources
resources :invoices do
resources :payments
end
The invoices model is as follows:
class Invoice < ActiveRecord::Base
belongs_to :customer, :inverse_of => :invoices
attr_accessible :due_date, :invoice_date, :reading_ids, :customer_id, :customer, :status, :amount, :balance
has_many :invoice_items, :dependent => :destroy
has_many :payments, :dependent => :destroy
end
The payments model is as follows:
class Payment < ActiveRecord::Base
attr_accessible :amount, :method, :payment_date, :reference_no, :invoice_id
belongs_to :invoice
end
The payments controller is as follows:
class PaymentsController < ApplicationController
before_filter :authenticate_user!
def new
invoice = Invoice.find(params[:invoice_id])
#payment = invoice.payments.build
respond_to do |format|
format.html #new.html.erb
end
end
end
I have created a view to record new payments and would like to display the customer details (name in particular) in this view, how do i go about it?
Payments view
<%= simple_form_for [#payment.invoice, #payment], :html => { :class => 'form-horizontal' } do |f| %>
<%= render "shared/error_messages", :target => #payment %>
<h5> Invoice Details </h5>
<%= f.input :invoice_id, disabled: true, as: :string %>
<%= f.input :method, as: :select, :collection => [['Cash','Cash'],['Cheque','Cheque'],['In-House transfer','In-House transfer'],['Account Ledger','Account ledger']], :selected => ['Cash','Cash'] %>
<%= f.input :reference_no, as: :string %>
<%= f.input :payment_date, as: :string, input_html: { class: "datepicker" } %>
<% end %>
Just use:
<%= #payment.invoice.customer.name %>
anywhere in the view.

Resources