rails grouped collection select for a join table - ruby-on-rails

I am creating a form for a "Review" model and i am trying to generate a nested select tag with professors and the courses they teach.
The association between professors and courses is many-to-many through the join table "Offering".
The review belongs to an offering and I want to get the IDs of the offerings inside the nested select tag.
Here are my models:
class Professor < ApplicationRecord
has_many :offerings, :dependent => :destroy
has_many :courses, :through => :offerings
has_many :reviews, :through => :offerings
end
class Course < ApplicationRecord
has_many :offerings, :dependent => :destroy
has_many :professors, :through => :offerings
end
class Offering < ApplicationRecord
belongs_to :professor
belongs_to :course
has_many :reviews
end
class Review < ApplicationRecord
belongs_to :offering
belongs_to :user
end
And here is the Review form:
<%= form_with(model: review, local: true) do |form| %>
<%= render 'shared/error_messages', locals: {resource: review} %>
<div class="form-group">
<%= form.label :body %>
<%= form.text_area :body, id: :review_body, class: 'form-control' %>
</div>
<div class="form-group">
<%= form.label :teaching_rating %>
<%= form.range_field :teaching_rating, in: 1..5, id: :review_teaching_rating, class: 'form-control slider' %>
</div>
<div class="form-group">
<%= form.label :offering %>
<%= form.grouped_collection_select :offering_id, Professor.order(:name), :courses, :name, :id, :name, class: 'form-control' %>
</div>
<div class="actions">
<%= form.submit "Submit", class: "btn btn-primary" %>
</div>
What should I pass as option_key_method parameter to the grouped_collection_select method to obtain the keys of the offerings correctly?
If there is a better approach like using two separate drop down lists for professors and courses (with the courses lists updating when the professor is selected) or using a different collection or any other approach please suggest it. I am new to rails.

Related

Create record using through association and nested_form_for rails

The following is my model structure
role.rb
has_many :user_roles
has_many :users, through: :user_roles
has_many :companies, through: :user_roles
user.rb
has_one :user_role, dependent: :destroy
has_one :role, through: :user_role
has_one :company, through: :user_role
company.rb
has_many :user_roles, dependent: :destroy
has_many :users, through: :user_roles
has_many :roles, through: :user_roles
user_role.rb
belongs_to :user
belongs_to :role, optional: true
belongs_to :company
I want to create record using association and nested form and right now I am able to create Company along with user using nested form, but I also want to create user_role for User.
I have included accepts_nested_attributes_for :users in company model.
and used fields_for to create user in company new form.
The following is my form
<%= form_for #company, html: { multipart: true } do |f| %>
<% if company.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(company.errors.count, "error") %> prohibited this company from being saved:</h2>
<ul>
<% company.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field form-group">
<%= f.label :name %>
<%= f.text_field :name, class: :"form-control" %>
</div>
<div class="field form-group">
<%= f.label :website %>
<%= f.text_field :website, class: :"form-control" %>
</div>
<div class="field form-group">
<%= f.label :phone %>
<%= f.text_field :phone, class: :"form-control" %>
</div>
<div class="field form-group">
<%= f.label :description %>
<%= f.text_area :description, class: :"form-control" %>
</div>
<div class="field form-group">
<%= f.file_field :company_image %>
</div>
<%= f.fields_for :users do |builder| %>
<%= render "users_fields", :f => builder %>
<% end %>
<div class="actions">
<%= f.submit class: :'btn btn-default' %>
</div>
<% end %>
Right now, the user_role is not created when creating the company. I'm not sure how to proceed.
Any guidance will be appreciated. Thanks in advance.
I want to create record using association and nested form and right now I am able to create Company along with user using nested form, but I also want to create user_role for User.
Before creating a user_role you need to commit and save to the db your user, otherwise you will run into a validation error.
user_role is not saved because the user_id you are setting does not correspond to a saved user
user_role belongs_to user. user_role.user_id must correspond to the id of an existing user (field id of a row in users). If you try to save user_role object and the user has not been already saved, you will trigger a validation error and the user_role will not be saved. Save the user in your controller before creating the user_role.
MODELS
1.company.rb
# put inverse_of otherwise it will throw error. To know more about inverse of go throw docs
has_many :user_roles, inverse_of: :company
has_many :users, through: :user_roles
has_many :roles, through: :user_roles
accepts_nested_attributes_for :user_roles
2.user_role.rb
belongs_to :user
belongs_to :role
belongs_to :company
# user_roles_attributes will accept nested attributes for both user and role
accepts_nested_attributes_for :role
accepts_nested_attributes_for :user
3.user.rb
has_many :user_roles#, inverse_of: :user
has_many :roles, through: :user_roles
has_many :company, through: :user_roles
4.role.rb
has_many :user_roles
has_many :users, through: :user_roles
has_many :companies, through: :user_roles
Companycontroller.rb
def new
#company = Company.new
urole = #company.user_roles.build
urole.build_user
urole.build_role
end
def create
#company = Company.new(company_params)
#company.save
end
private
def company_params
# here put associate modal attributes to permit.
params.require(:company).permit(:company_name,
user_roles_attributes: [
role_attributes: [:role_name],
user_attributes: [:user_name, :email]
]
)
end
form.html.erb
<%= form_for #company, html: { multipart: true } do |f| %>
<%=f.fields_for :user_roles do |user_roles_builder| %>
--USER DETAILS--
<br>
<%=user_roles_builder.fields_for :user do | user_builder | %>
<%= render "users_fields", :f => user_builder %>
<% end %>
<br>
-- ROLE DETAILS--
<br>
<%=user_roles_builder.fields_for :role do | role_builder | %>
<%= render "users_fields", :f => role_builder %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Follow this and it should work for you

Rails Multiple Associations

I'm having trouble setting up my associations. I'm trying to set up Courses to have different Prices depending on the Season and amount of alumns. It gets even more complicated when Seasons have different date ranges for the same Season, like for instance the first Season is from 12/24/2014 to 12/31/2014 but also from 01/07/2015 to 01/14/2015. For this I created another model Season_dates.
I can't figure out how to set up my associations, here's what I have got so far:
class Season < ActiveRecord::Base
has_many :season_dates
has_many :prices, through: :season_dates
end
class SeasonDate < ActiveRecord::Base
belongs_to :price
belongs_to :seasons
end
class Price < ActiveRecord::Base
belongs_to :course
has_many :season_dates
has_many :seasons, through: :season_dates
accepts_nested_attributes_for :season_dates
end
class Course < ActiveRecord::Base
has_many :prices
end
Form:
<%= form_for #price do |f| %>
<div class="field">
<%= f.fields_for :couse do |course_f| %>
<%= course_f.label :course %><br>
<%= course_f.collection_select :course_id, Course.all, :id, :name, {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field">
<%= f.label :alumn %><br>
<%= f.number_field :alumn, in: 1...11, step: 1, class: 'form-control' %>
</div>
<div class="field">
<%= f.fields_for :season_date do |season_f| %>
<%= season_f.label :season %><br>
<%= season_f.select :season_id, options_from_collection_for_select(Season.all, :id, :name), {}, {class: 'form-control'} %>
<% end %>
</div>
<div class="field form-group">
<%= f.label :price %><br>
<%= f.number_field :price, in: 0.01..999.99, step: 0.01, placeholder: "0.00€", class: 'form-control' %>
</div>
<div class="actions">
<%= f.submit class: 'btn btn-default' %>
</div>
<% end %>
I want to be able to call price.season.name or price.course.name. I'm not sure how to proceed, any help is appreciated.
I think you might be complicating the scenario a bit. Is there a reason that SeasonDate is its own class? Is there a way you can model like this?
class Season < ActiveRecord::Base
has_many :courses
# I would have on this model the attributes of from_date and
# to_date removing the need for a SeasonDate class
end
class Course < ActiveRecord::Base
belongs_to :season
# You might need to model this as a has_and_belongs_to_many relationship
# with a Season if a Course can belong to many seasons
end
class Price < ActiveRecord::Base
belongs_to :course
belongs_to :season
end
These models would give you methods such as:
#season.courses # would return all courses in a particular season
#price.season.name
#price.course.name
#course.prices # would return all prices associated with a particular course
If you do go for the habtm association, meaning a course can belong to many seasons, you could do something like this (guessing at your price attribute names) in your views.
<%= #course.name %>
<% #course.prices.each do |price| %>
<%= price.season.name %> : <%= price.price_in_dollars %>
<% end
This would allow you to iterate over all prices for a course and display which season they are applicable for so each person can find the best price for them.

Creating a form based on a :has_many through relationship

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 %>

form_for with ckeckbox_tag from other model

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 %>

Rails 3, how to update habtm relation with single check_box_tag or Confirm-/Refuse-Buttons

I have a habtm model like:
class Recurrence < ActiveRecord::Base
has_many :participations, :include => :user
has_many :users, :through => :participations
accepts_nested_attributes_for :participations
attr_accessible :scheduled_to, :user_id, :user_ids
end
class Participation < ActiveRecord::Base
belongs_to :recurrence
belongs_to :user
attr_accessible :recurrence_id, :user_id
end
class User < ActiveRecord::Base
has_many :participations, :dependent => :delete_all
has_many :recurrences, :through => :participations
accepts_nested_attributes_for :participations
attr_accessible :name, :email, :phone, :recurrence_ids
end
with standard actions for the recurrences_controller (index, show, new, edit, create, update, destroy).
In the view of a single recurrence (/recurrences/10 -> show-action), I try to create/update the participation of user. When I do in the mentioned view something like:
<%= form_for #recurrence do |f| %>
<div class="checkbox">
<% for user in User.find(:all) %>
<div>
<%= check_box_tag "recurrence[user_ids][]", user.id, #recurrence.users.include?(user) %>
<%= user.name %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit "Update", :class => 'btn btn-mini btn-primary' %>
</div>
<% end %>
erverything is working fine, I can add or remove the participation for one or more users.
BUT I like to do it - for just a single user, namely the current_user! I tried with the following source:
<%= form_for(#recurrence) do %>
<%= check_box_tag "recurrence[user_id]", current_user.id,
#recurrence.users.include?(current_user) %>
<%= current_user.name %>
<%= submit_tag "Update" %>
<% end %>
which is not working, more detailed
Updating the not changed status: not particpating, doesn't do anything: correct!
Changing status: from not participating - to participating, works for current_user, BUT will also delete the status of a other users: wrong!
Changing status: from participating - to not participating, won't change anything: wrong!
Any help is welcome!
Finaly I want to reduce the Check-Box to Confirm-/Refuse-Buttons with hidden-fields for the recurrence, but proabably there is easier rails-way?

Resources