Multilevel select on rails - ruby-on-rails

I want to use multiple select drop-down between several models
I have this:
class Report < ActiveRecord::Base
belongs_to :region
end
class City < ActiveRecord::Base
has_many :regions
end
class Region < ActiveRecord::Base
has_many :reports
belongs_to :city
end
when I select a city I want to pull list of items from selected city and show it on next drop-down list. How do I create relationships between drop-down menus ? Can anyone help me?
Thanks.

This link may help you in doing it.
Rails 2 + Prototype
app/models/cities.rb
class City < ActiveRecord::Base
has_many :regions
has_many :reports, :through => :regions # this is newly added
end
cities_controller
class CitiesController < ApplicationController
def index
#cities = City.find(:all)
#regions = Region.find(:all)
#reports = Report.find(:all)
end
def update_regions
# updates regions and reports based on city selected
city = City.find(params[:city_id])
regions = city.regions
reports = city.reports
render :update do |page|
page.replace_html 'regions', :partial => 'regions', :object => regions
page.replace_html 'reports', :partial => 'reports', :object => reports
end
end
def update_reports
# updates reports based on region selected
region = Region.find(params[:region_id])
reports = region.reports
render :update do |page|
page.replace_html 'reports', :partial => 'reports', :object => reports
end
end
end
_reports.html.erb
<%= collection_select(nil, :report_id, reports, :id, :title,
{:prompt => "Select a Report"}) %>
_regions.html.erb
<%= collection_select(nil, :region_id, regions, :id, :name,
{:prompt => "Select a Region"},
{:onchange => "#{remote_function(:url => {:action => "update_reports"},
:with => "'region_id='+value")}"}) %>
<br/>
index.html.erb
<%= javascript_include_tag :defaults %>
<%= collection_select(nil, :city_id, #cities, :id, :name,
{:prompt => "Select a City"},
{:onchange => "#{remote_function(:url => {:action => "update_regions"},
:with => "'city_id='+value")}"}) %>
<br/>
<div id="regions"><%= render :partial => 'regions', :object => #regions %></div>
<div id="reports"><%= render :partial => 'reports', :object => #reports %></div>

Related

How to assign jobs to a ship as a many-to-many relationship

I have a shipping project where I can create ships and jobs. I have a many-to-many relationship with jobs and ships, but I'm having trouble creating new jobs for a ship.
I want a new link to assign jobs for a specific boat via check-boxes but I get an error when I click on the link to assign jobs when no route matches get "/ship/all_jobs".
This is my Ship model:
class Ship < ApplicationRecord
has_and_belongs_to_many :jobs
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
validates :name, uniqueness: true
end
This is my Job model:
class Job < ApplicationRecord
has_and_belongs_to_many :ships
validate :price_has_to_be_greater_than_minimum
validates :title, uniqueness: true
validates :description, length: { minimum: 50 }
def price_has_to_be_greater_than_minimum
errors.add(:cost, "price has to be greater than 1000") if
!cost.blank? and cost > 1000
end
end
This is the Jobship join table:
class Jobship < ApplicationRecord
belongs_to :ships
belongs_to :jobs
end
and my ships controller:
def all_jobs
#ship = Ship.find(params[:id])
end
def create
#ship = Ship.new(ship_params)
if #ship.save
flash[:notice] = 'Ship record was successfully created.'
redirect_to(#ship)
else
render :action => "new"
end
end
def save
#ship = Ship.find(params[:id])
#job = Job.find(params[:job])
if params[:show] == "true"
#ship.jobs << #ship
else
#ship.jobs.delete(#ship)
end
#ship.save!
render :nothing => true
end
private
def ship_params
params.require(:ship).permit(:name, :location, :avatar)
end
end
This is the all_jobs view:
<h1>jobs for <%= #ship.name %></h1>
<table>
<tr>
<th>assignl</th>
<th>job</th>
</tr>
<%= form_for (#ship) do |f| %>
<%= f.label "jobs" %><br />
<%= f.collection_check_boxes :job_ids, Job.all, :id, :title do |b| %>
<div class="collection-check-box">
<%= b.check_box %>
<%= b.label %>
<%= f.submit %>
<%end%>
<%end%>
This is the link to all jobs from the index view:
<%= link_to 'New ship', new_ship_path %>
<% #ships.each do |ship| %>
<h1>ship name</h1><%=ship.name%><h1> ship location</h1> <%= ship.location %> <%= link_to 'Show', ship %>
<%= link_to 'jobs', ship_all_jobs_path(ship) %>
<%= link_to "all jobs", jobs_path %>
<% end %>
And my routes:
Rails.application.routes.draw do
devise_for :users
resources :ships
resources :jobs
root :to => "ships#index"
post "ship/all_jobs", :to=> "ships#save"
get "ship/all_jobs/:id", :to => "ships#all_jobs"
end
First of all you are going all wrong about many to many relationships in rails, you don't need separate model for the join table, active record takes care of it read here http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association to learn more; so you don't need the Jobship model.
class Jobship < ApplicationRecord
belongs_to :ships
belongs_to :jobs
end
You have to put / before you define your routes:
Rails.application.routes.draw do
devise_for :users
resources :ships
resources :jobs
root :to => "ships#index"
post "/ship/all_jobs", :to=> "ships#save"
get "/ship/all_jobs/:id", :to => "ships#all_jobs"
end
also you can see your defined routes using rails routes in the command line.

Rails 3 - How to edit single nested polymorphic resource?

In my Rails 3.0 app I have a Client model and a polymorphic Addresses model. As per the code below a client can have many addresses. I would like to my form to update a single client address at a time. I can only seem to get the [addresses_attributes] to appear if I allow all of the client's addresses to be edited at the same time. Is there a way around this?
class Client < ActiveRecord::Base
has_many :addresses, :as => :addressable, :dependent => :destroy
accepts_nested_attributes_for :addresses
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
Clients Controller
def edit
#client = Client.find(params[:id])
#addresses = #client.addresses
if params[:address]
#address = #client.addresses.find(params[:address])
else
#addresses ? #address = #addresses.first : #address = []
end
end
def update
#client = Client.find(params[:id])
#client.update_attributes(params[:client])
redirect_to client_path(#client)
end
View
<%= form_for #client do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= f.fields_for #address do |addresses_attributes| %>
<%= render :partial => 'addresses/fields', :locals => {:f => addresses_attributes} %>
<% end %>
<%= f.submit %>
<% end %>
EDIT:
Sorry, I reread the post and realized that there were better options. You should add a scope to the Address model or you should create separate associations in the Client using conditions.
http://railscasts.com/episodes/108-named-scope
or see conditions here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
DETAIL:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
named_scope :type_one, :conditions => { :address_type => 'one' }
named_scope :type_two, :conditions => { :address_type => 'two' }
<%= f.fields_for #address.type_one do |addresses_attributes| %>
<%= render :partial => 'addresses/fields', :locals => {:f => addresses_attributes} %>
<% end %>

Rails nested model with formtastic is skipping one field?

I have this structure models
class Tournament < ActiveRecord::Base
AGES = ["5u", "6u", "7u", "8u"]
has_many :courts, :dependent => :destroy
accepts_nested_attributes_for :courts, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
class Court < ActiveRecord::Base
belongs_to :tournament, :autosave => true
has_many :ages, :dependent => :destroy
accepts_nested_attributes_for :ages, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
class Age < ActiveRecord::Base
belongs_to :court
Now my forms look like this
_form.html.erb
<%= semantic_form_for #tournament do |f| %>
<%= f.inputs do %>
<%= f.input :name, :hint => "What is the name of the Tournament?" %>
<%= f.semantic_fields_for :courts do |builder| %>
<%= render :partial => "court_fields", :locals => { :f => builder } %>
<% end %>
_court_fields.html.erb
<div class="nested_fields">
<%= f.input :name, :input_html => {:class => "name"} %>
<%= f.semantic_fields_for :ages do |builder| %>
<%= render :partial => "age_fields", :locals => { :f => builder } %>
<% end %>
_age_fields.html.erb
Testing ...am I getting in here
<%= f.input :name, :as => :check_boxes, :collection => Tournament::AGES, :input_html => {:class => "age_limits"} %>
everything seems to work well except nothing shows up in the ages_fields partial...not the checkboxes and not even the dummy text Testing ...am I getting in here is not displaying....any ideas what could be causing the issue
The obvious reason I can think of: are you sure your Court has ages ?
[EDIT] That the Court has the relation was indeed clear to me.
But your code will only show an age for a court if it already exists.
From your output in the comments: the court has no actual ages so no ages are shown.
If you do this in your controller:
def new
#tournament = Tournament.new
#tournament.courts.build
#tournament.courts[0].ages.build
end
This will make sure that you have at least one (empty) court and one (empty) age.
Otherwise you could also consider using a gem like cocoon to dynamically add new elements if needed.
Hope this helps.

Create/edit using a 3 column join table

As a previous post was asking (Alias table name to facilitate 3 column join table (MySQL or PostgreSQL)), I am working on a join table that joins 3 tables, Project, Employee, Role. The use of the :join_table => "my_join_table" works fine when I want to display information coming from the join tables. However, during the create action, the insert into SQL request is done in two times:
INSERT INTO properties_roles_users (project_id, employee_id) VALUES (11, 14)
and
INSERT INTO properties_roles_users (role_id, project_id) VALUES (5, 11)
instead of having only one insert into with the 3 fields.
I use the habtm relationship.
Any Idea how to get the INSERT INTO that would have all three ID (employee_id, project_id, role_id)?
[EDIT]
Ok, I was using part of the code from the other post so it would make sense in the context... we should then read "employees_projects_roles". Any who, let say I'll keep on going with user, property and role. Here's the code from my view:
<% form_for(#property,:html => { :multipart => true }) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :address %><br />
<%= f.text_field :address %>
</p>
( ... code ... )
<p>
<%= f.label :role, 'Role' %><br />
<%= f.collection_select :role_ids, Role.find(:all, :order => 'role'), :id, :role, {}, :multiple => true %>
</p>
<%= f.hidden_field :user_ids, :value => current_user.id %>
<%= render :partial => 'form', :locals => { :f => f } %>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>
Controller (properties_controller:
def create
#property = Property.new(params[:property])
respond_to do |format|
if #property.save
flash[:notice] = 'Property was successfully created.'
format.html { redirect_to(#property) }
format.xml { render :xml => #property, :status => :created, :location => #property }
else
format.html { render :action => "new" }
format.xml { render :xml => #property.errors, :status => :unprocessable_entity }
end
end
end
Models:
class User < ActiveRecord::Base
has_and_belongs_to_many :properties, :join_table => "properties_roles_users"
has_and_belongs_to_many :roles, :join_table => "properties_roles_users"
(... other useful stuff ...)
end
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => "properties_roles_users"
has_and_belongs_to_many :properties, :join_table => "properties_roles_users"
end
class Property < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => "properties_roles_users"
has_and_belongs_to_many :roles, :join_table => "properties_roles_users"
attr_accessible (...:different_fields...) :user_ids, :role_ids
end
Got it. It seems that I needed to write an :insert_sql statement in the habtm declaration such as:
has_and_belongs_to_many :users,
:join_table => "projects_roles_users",
:foreign_key => 'role_id',
:association_foreign_key => 'project_id',
:insert_sql => 'INSERT INTO
projects_roles_users(project_id,role_id,user_id)
VALUES(#{id}, #{role_ids}, #{user_ids})'

Rails 3, nested multi-level forms and has_many through

I'm trying to get it to work but it dosen't!
I have
class User < ActiveRecord::Base
has_many :events, :through => :event_users
has_many :event_users
accepts_nested_attributes_for :event_users
end
class Event < ActiveRecord::Base
has_many :event_users
has_many :users, :through => :event_users
accepts_nested_attributes_for :users
end
class EventUser < ActiveRecord::Base
set_table_name :events_users
belongs_to :event
belongs_to :user
accepts_nested_attributes_for :events
accepts_nested_attributes_for :users
end
And also the table-layout
event_users
user_id
event_id
user_type
events
id
name
users
id
name
And this is my form
<%= semantic_form_for #event do |f| %>
<%= f.semantic_fields_for :users, f.object.users do |f1| %>
<%= f1.text_field :name, "Name" %>
<%= f1.semantic_fields_for :event_users do |f2| %>
<%= f2.hidden_field :user_type, :value => 'participating' %>
<% end %>
<% end %>
<%= link_to_add_association 'add task', f, :users %>
<% end %>
The problem is that if I create a new user this way, it doesn't set the value of user_type (but it creates a user and a event_users with user_id and event_id). If I go back to the edit-form after the creation of a user and submit, then the value of user_type is set in events_users. (I have also tried without formtastic)
Any suggestions? Thanks!
----edit----
I have also tried to have the event_users before users
<%= semantic_form_for #event do |f| %>
<%= f.semantic_fields_for :event_users do |f1| %>
<%= f1.hidden_field :user_type, :value => 'participating' %>
<%= f1.semantic_fields_for :users do |f2| %>
<%= f2.text_field :name, "Name" %>
<% end %>
<% end %>
<%= link_to_add_association 'add task', f, :event_users %>
<% end %>
but then it only throws me an error:
User(#2366531740) expected, got
ActiveSupport::HashWithIndifferentAccess(#2164210940)
--edit--
the link_to_association is a formtastic-cocoon method (https://github.com/nathanvda/formtastic-cocoon) but I have tried to do other approaches but with the same result
---edit----
def create
#event = Event.new(params[:event])
respond_to do |format|
if #event.save
format.html { redirect_to(#event, :notice => 'Event was successfully created.') }
format.xml { render :xml => #event, :status => :created, :location => #event }
else
format.html { render :action => "new" }
format.xml { render :xml => #event.errors, :status => :unprocessable_entity }
end
end
end
To be honest, i have never tried to edit or create a has_many :through in that way.
It took a little while, and had to fix the js inside formtastic_cocoon to get it working, so here is a working solution.
You need to specift the EventUser model, and then fill the User model (the other way round will never work).
So inside the models you write:
class Event < ActiveRecord::Base
has_many :event_users
has_many :users, :through => :event_users
accepts_nested_attributes_for :users, :reject_if => proc {|attributes| attributes[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :event_users, :reject_if => proc {|attributes| attributes[:user_attributes][:name].blank? }, :allow_destroy => true
end
class EventUser < ActiveRecord::Base
belongs_to :user
belongs_to :event
accepts_nested_attributes_for :user
end
class User < ActiveRecord::Base
has_many :events, :through => :event_users
has_many :event_users
end
Then the views. Start with the events/_form.html.haml
= semantic_form_for #event do |f|
- f.inputs do
= f.input :name
%h3 Users (with user-type)
#users_with_usertype
= f.semantic_fields_for :event_users do |event_user|
= render 'event_user_fields', :f => event_user
.links
= link_to_add_association 'add user with usertype', f, :event_users
.actions
= f.submit 'Save'
(i ignore errors for now)
Then, you will need to specify the partial _event_user_fields.html.haml partial (here comes a little bit of magic) :
.nested-fields
= f.inputs do
= f.input :user_type, :as => :hidden, :value => 'participating'
- if f.object.new_record?
- f.object.build_user
= f.fields_for(:user, f.object.user, :child_index => "new_user") do |builder|
= render("user_fields", :f => builder, :dynamic => true)
and to end the _user_fields partial (which does not really have to be a partial)
.nested-fields
= f.inputs do
= f.input :name
This should work.
Do note that i had to update the formtastic_cocoon gem, so you will need to update to version 0.0.2.
Now it would be easily possible to select the user_type from a simple dropdown, instead of a hidden field, e.g. use
= f.input :user_type, :as => :select, :collection => ["Participator", "Organizer", "Sponsor"]
Some thoughts (now i proved it works):
this will always create new users on the fly, actually eliminating the need for the EventUser. Will you allow selecting existing users from a dropdown too?
personally i would turn it around: let users assign themselves to an event!
Does the events_users model not have an ID column? Since there's an additional field (user_type) then EventUser is a model and should probably have an ID. Maybe that's why user_type isn't being set in your first case.

Resources