I am making a model where users can belong to multiple teams and teams have multiple people.
I have checkboxes but they don't pass the value onto the object.
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :teams
accepts_nested_attributes_for :teams
end
class Team < ActiveRecord::Base
has_many :users
attr_accessible :name
end
Here is the code in my controller
def create
#users = User.all
#user = User.new
#teams = Team.all
#user.attributes = {:teams => []}.merge(params[:user] || {})
end
Here is the code in my view file
<%= form_for #user, url: {action: "create"} do |f| %>
<%= f.label :teams%>
<% for team in #teams %>
<%= check_box_tag team.name, team.name, false, :teams => team.name%>
<%= team.name -%>
<% end %>
<%= submit_tag "Create User" %>
I am trying to show it into
<%= user.teams.name %>
But the only output is "Team"
Can someone tell me what I am doing wrong?
Actually, you can't do a many-to-many relationship that way... you need to do has_many :through or alternatively has_and_belongs_to_many Nice explanation here...
http://guides.rubyonrails.org/association_basics.html
Related
I'm kinda new to ruby on rails, I've been reading documentation on assosiations and I've been having an easy time (and usually a quick google search solves most of my doubts) however recently I'm having problems with a seemingly easy thing to do.
What I'm trying to do is to create an Event, linked to an existing Category.
Event model
class Event < ApplicationRecord
has_many :categorizations
has_many :categories, through: :categorizations
accepts_nested_attributes_for :categorizations
.
.
.
end
Category model
class Category < ApplicationRecord
has_many :categorizations
has_many :events, through: :categorizations
end
Categorization model
class Categorization < ApplicationRecord
belongs_to :event
belongs_to :category
end
Event controller
class EventsController < ApplicationController
def new
#event = Event.new
end
def create
#user = User.find(current_user.id)
#event = #user.events.create(event_params)
if #event.save
redirect_to root_path
else
redirect_to root_path
end
end
private
def event_params
params.require(:event).permit(:name, category_ids:[])
end
Here is the form, which is where I think the problem lies:
<%= form_for #event, :html => {:multipart => true} do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :categorizations do |categories_fields|%>
<% categories = [] %>
<% Category.all.each do |category| %>
<% categories << category.name %>
<% end %>
<%= categories_fields.label :category_id, "Category" %>
<%= categories_fields.select ( :category_id, categories) %>
<% end %>
.
.
.
<%= f.submit "Create"%>
<% end %>
I previously populate the Category db with some categories, so what's left to do is to while creating an event, also create a categorization that is linked both to the new event and the chosen Categorization. but the things I've tried don't seem to be working.
Other things seem to be working ok, whenever I try to submit the event all things are populated as expected except the categorization.
As you mentioned that you are new to rails, you'll find this cocoon gem very interesting. You can achieve what you wanted. And the code will cleaner.
I don't have the points to comment, that's why I am giving this as an answer.
I have a few models in my project : Request, Work, Car and Employee. Work is an intermediate model between Request and Car/Employee.
Here are the associations:
Request
has_many :works, dependent: :destroy
def performers
works.map {|x| x.performer}
end
Work
belongs_to :request
belongs_to :performer, polymorphic: true
Car
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
Employee
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
View used to create works:
<%= form_for([#request, #work]) do |f| %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) if #request.type == "StaffRequest" %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) if #request.type == "CarRequest" %>
<%= f.submit 'OK' %>
<% end %>
Work controller
def new
#work = #request.works.new
end
def create
#work = #request.works.new(work_params)
end
def work_params
params.require(:work).permit(:performer_id, :request_id)
end
The problem is that my performer_type column is always empty, it does not save the class name. What can be the problem? Any ideas?
It's empty because you did't pass it, you should add a hidden field for you form:
<%= form_for([#request, #work]) do |f| %>
<% if #request.type == "StaffRequest" %>
<%= (f.hidden_field :performer_type, value: "Employee") %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) %>
<% elsif #request.type == "CarRequest" %>
<%= (f.hidden_field :performer_type, value: "Car") %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) %>
<% end %>
<%= f.submit 'OK' %>
<% end %>
Beside :performer_id, you have to pass the :performer_type also, one way to do this is via the form select_tag :
def create
#work = #request.works.new(work_params)
end
def work_params
# use :performer if you use :performer as in the select form field
params.require(:work).permit(:performer, :request_id)
# OR
# use :performer_id & :performer_type if you also use the hidden field
params.require(:work).permit(:performer_id, :performer_type, :request_id)
end
There is a good example (for Rails 4.2) of using a single select form field for polymorphic so you can write like:
<%= f.grouped_collection_select :global_performer, [ Car, Employee ], :all, :model_name, :to_global_id, :name %>
How to create grouped select box in Rails for polymorphic association using Global ID?
My Models:
class Event < ActiveRecord::Base
belongs_to :organization
has_many :directors
has_many :vips, :through => :directors
end
class Vip < ActiveRecord::Base
belongs_to :organization
has_many :directors
has_many :events, :through => :directors
end
class Director < ActiveRecord::Base
belongs_to :vip
belongs_to :event
end
My New Event form:
<%= form_for [#organization, #event] do |f| %>
<p>
<%= f.label :when %>
<%= f.date_select :when %>
</p>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :vip %>
<%= f.select :vip_id, options_for_select(#organization.vips.all.map {|v| [v.name, v.id]}) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
And my Events Controller:
def new
#organization = Organization.find(params[:organization_id])
#event = #organization.events.new
#director = Director.new
end
def create
#organization = Organization.find(params[:organization_id])
#event = #organization.events.build(event_params)
if #event.save
redirect_to organization_path(#organization)
else
render 'new'
end
end
So, my Vips are created earlier in the process and sit in the vips table. When I submit the new event form, I get a new entry to my events table just fine. What I want to do is have my directors table be populated with a new entry when I submit the new events form. The directors table would need the event_id of the event I just created, and the vip_id from the select tag in the form.
I thought about adding this to the create action
def create
#director = Director.new
if #event.save
redirect_to organization_path(#organization)
#director.vip_id = #event.vip_id
#director.event_id = #event.id
But that didn't create an entry into the director table. Is there a way to do this that I'm not seeing?
#director.vip_id = #event.vip_id
#director.event_id = #event.id
So, you have these two assignments, #director.event_id = #event.id this one is fine because you just created the event and you have the #event.id.
But, the first one won't work. Looking at your Model associations, #event does not have a vip_id, so you can't call #event.vip_id. You have to go to the vip through the organization, something like:
#event.organization.vips.first.vip_id
or, #event.vips.first.vip_id this would work too as you have :through => :directors association.
These two are the only way I see to get a valid vip_id corresponding to the event. Although, this will only get the first vip_id or you can specify some criteria in a where clause to get a particular vip_id for that event.
If that works for you, good. Otherwise, you may have to re-think your associations among the models.
When I submit this form, it is creating 2 identical records in the Members table (the fields_for part of the form). Please help me understand why that is happening.
The basic setup is: a Comp has many Teams and a Team has many Members. When creating a new Team, the first Member created should be the team's secretary (which means the secretary_flag field in the Members table should be set to TRUE.) This form below is supposed to create a new Team, create the first team member, and mark that team member as the secretary.
The controller:
def new
#comp = Comp.find(params[:comp_id])
#team = #comp.teams.new
#team.members.build
end
def create
#comp = Comp.find(params[:comp_id])
#team = #comp.teams.create(params[:team])
if #team.update_attributes(params[:team])
flash[:success] = "Team added successfully."
redirect_to new_comp_team_member_path(#comp,#team)
else
render 'new'
end
end
The form view:
<%= form_for [#comp,#team] do |builder| %>
<%= builder.label :team_name, "Team name" %>
<%= builder.text_field :team_name %>
<%= builder.fields_for :members do |f| %>
<%= f.label :member_email, "Email address of team secretary" %>
<%= f.text_field :member_email %>
<%= f.hidden_field :secretary_flag, :value => 1 %>
<% end %>
<%= builder.submit "Create new team" %>
<% end %>
And in my routes:
resources :comps do
resources :teams do
resources :members
end
end
And in my models:
comp.rb:
attr_accessible :teams_attributes
has_many :teams, :dependent => :destroy
accepts_nested_attributes_for :teams, :allow_destroy => :true
team.rb:
attr_accessible :members_attributes
belongs_to :comp
has_many :members
accepts_nested_attributes_for :members
member.rb:
belongs_to :team
The solution I figured out was very basic. In my create action I accidentally put:
if #team.update_attributes(params[:team])
when it should have been:
if #team.save(params[:team])
I still don't understand why that would have created 2 identical records though, but it now works.
I'm relatively new to Ruby on Rails so please don't mind my newbie level!
I have following models:
class Paintingdescription < ActiveRecord::Base
belongs_to :paintings
belongs_to :languages
end
class Paintingtitle < ActiveRecord::Base
belongs_to :paintings
belongs_to :languages
end
class Painting < ActiveRecord::Base
has_many :paintingtitles, :dependent => :destroy
has_many :paintingdescriptions, :dependent => :destroy
has_many :languages, :through => :paintingdescriptions
has_many :languages, :through => :paintingtitles
end
class Language < ActiveRecord::Base
has_many :paintingtitles, :dependent => :nullify
has_many :paintingdescriptions, :dependent => :nullify
has_many :paintings, :through => :paintingtitles
has_many :paintings, :through => :paintingdescriptions
end
In my painting new/edit view, I would like to show the painting details, together with its title and description in each of the languages, so I can store the translation of those field.
In order to build the languagetitle and languagedescription records for my painting and each of the languages, I wrote following code in the new method of my Paintings_controller.rb:
#temp_languages = #languages
#languages.size.times{#painting.paintingtitles.build}
#painting.paintingtitles.each do |paintingtitle|
paintingtitle.language_id = #temp_languages[0].id
#temp_languages.slice!(0)
end
#temp_languages = #languages
#languages.size.times{#painting.paintingdescriptions.build}
#painting.paintingdescriptions.each do |paintingdescription|
paintingdescription.language_id = #temp_languages[0].id
#temp_languages.slice!(0)
end
In form partial which I call in the new/edit view, I have
<% form_for #painting, :html => { :multipart => true} do |f| %>
...
<% languages.each do |language| %>
<p>
<%= label language, language.name %>
<% paintingtitle = #painting.paintingtitles[counter] %>
<% new_or_existing = paintingtitle.new_record? ? 'new' : 'new' %>
<% prefix = "painting[#{new_or_existing}_title_attributes][]" %>
<% fields_for prefix, paintingtitle do |paintingtitle_form| %>
<%= paintingtitle_form.hidden_field :language_id%>
<%= f.label :title %><br />
<%= paintingtitle_form.text_field :title%>
<% end %>
<% paintingdescription = #painting.paintingdescriptions[counter] %>
<% new_or_existing = paintingdescription.new_record? ? 'new' : 'new' %>
<% prefix = "painting[#{new_or_existing}_title_attributes][]" %>
<% fields_for prefix, paintingdescription do |paintingdescription_form| %>
<%= paintingdescription_form.hidden_field :language_id%>
<%= f.label :description %><br />
<%= paintingdescription_form.text_field :description %>
<% end %>
</p>
<% counter += 1 %>
<% end %>
...
<% end %>
But, when running the code, ruby encounters a nil object when evaluating paintingdescription.new_record?:
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.new_record?
However, if I change the order in which I
a) build the paintingtitles and painting descriptions in the paintings_controller new method and
b) show the paintingtitles and painting descriptions in the form partial
then I get the nil on the paintingtitles.new_record? call.
I always get the nil for the objects I build in second place. The ones I build first aren't nil in my view.
Is it possible that I cannot build objects for 2 different associations at the same time? Or am I missing something else?
Thanks in advance!
Actually I found a pretty simple solution. I provide a hash with values for the language ids when building the records.
#languages = Language.all
#languages.each do |language|
#painting.paintingtitles.build( {:language_id => language.id} )
#painting.paintingdescriptions.build( {:language_id => language.id} )
end