Many to Many relation issue in Rails 4 - ruby-on-rails

I am a rails beginner and encountered the following issue
Models are setup as follows (many to many relation):
class Activity < ActiveRecord::Base
belongs_to :user
has_many :joinings
has_many :attendees, through: :joinings
end
class Joining < ActiveRecord::Base
belongs_to :activity
belongs_to :attendee
end
class Attendee < ActiveRecord::Base
has_many :joinings
has_many :activities, through: :joinings
end
This is one page test application for some users posting some activities, and other users to join the activities.
It is organized as single page format (activities index), and after each activity, there is a "Join" button users can click.
I am stuck at the point when a user needs to join a specific activity.
in the index.html.erb (of the activities), with the Join button code.
This will point to the attendee controller, to Create method, but I got no information regarding the Activity that I want to follow (eg. activity_id, or id)
Without this I cannot use the many to many relation to create the attendee.
What would be the correct button code, or any other suggestion to to get the corresponding activity ID in the attendees controller?
I tried a lot of alternatives, including even session[current_activity] , but is pointing (of course) always to the last activity.
Thanks so much !

If you have existing activities, and existing attendees, and you want to change the relationship between them, then you are editing the join table records. Therefore, you should have a controller for these. Like i said in my comment i'd strongly recomnmend renaming "joining" to "AttendeeActivity" so your schema looks like this:
class Activity < ActiveRecord::Base
belongs_to :user
has_many :attendee_activities
has_many :attendees, through: :attendee_activities
end
class AttendeeActivity < ActiveRecord::Base
belongs_to :activity
belongs_to :attendee
end
class Attendee < ActiveRecord::Base
has_many :attendee_activities
has_many :activities, through: :attendee_activities
end
Now, make an AttendeeActivitiesController, with the standard scaffoldy create/update/destroy methods.
Now, when you want to add an attendee to an activity, you're just creating an AttendeeActivity record. if you want to remove an attendee from an activity, you're destroying an AttendeeActivity record. Super simple.
EDIT
If you want to create an Attendee, and add them to an activity at the same time, then add a hidden field to the form triggered by the button:
<%= hidden_field_tag "attendee[activity_ids][]", activity.id %>
This will effectively call, when creating the attendee,
#attendee.activity_ids = [123]
thus adding them to activity 123 for example.

You have several options here. I'm assuming that the Join button will simply submit a hidden form to the attendees controller's create action. So the simplest solution would be to include the activity_id as a hidden form tag that gets submitted along with the rest of the form. This activity_id will be available in the params hash in the controller.
The other option is to setup Nested routing so that the activity_id is exposed via the path.

Thanks for all the details. I will change the naming of the join table for the future.
My problem was that I could not find the specific activity for attendee create method. Finally I found something like this for the JOIN button:
<%= button_to 'Join', attendees_path(:id => activity) %>
This will store the Activity ID, so I am able to find it in the Attendees controller:
def create
activity = Activity.find(params[:id])
#attendee = activity.attendees.create user_id: current_user.id
redirect_to activities_path
end
this updates also the Joinings (AttendeeActivity) table.
I will study about the hidden_field_tag solution, as is not clear to me yet.

Related

Dynamic select and filter in Rails 4

Hi I'm a beginner to Rails and I've been struggling to create a filter feature, I've done some googling but I feel like I'm in a bottleneck situation right now, would really need some help.
Mock up:
I have an Event model, with title, description etc, and now I want to add Court, House and Event type into the model. When a user create an event, they must choose a court, a house and what type of event it is.
User must choose a court then select a house, as each house name is different in each court.
Preferably the house dropdown should only appear after court value is selected.
The most important part is the users can filter their search later on, and get a list of events based on the selections they've made.
/events?court=foo&house=bar&event_type=fun
And it's ok if the user only choose one choice and clicked Search
/events?court=foo # show all foo court events
/events?court=foo&event_type=fun # show all fun type events at foo court
My Questions
From some answers I've seen, some people have created seperate models for Court, House etc. Is that necessary in this case? I'd like to keep it all in Event.rb, so I can do
validates :court, :house, :event_type, presence: true
For the View, we would also need JavaScript right? Do we use it along side with a Event method like this?
def return_house(selected_court)
if selected_court == 'foo'
['bar1', 'bar2', 'bar3']
elsif selected_court == 'baz'
['qux1', 'qux2', 'qux3']
end
end
I've been using f.input for dropdown selections, but I've seen people use f.collection_select?
Because a court can be associated with multiple events, you'll need to create separate models and use a one_to_many relationship.
class Event < ActiveRecord::Base
has_one :court, through: :event_court
end
class EventCourt < ActiveRecord::Base
belongs_to :event
belongs_to :court
end
class Court < ActiveRecord::Base
has_many :event_courts
has_many :events, through: :event_court
end
You'll also want to do a similar thing for event_type.
This type of setup is why you see other people using collection_select.
I assume a court can also have multiple houses, so you'll want to create a has_many relationship between courts and houses
class Court < ActiveRecord::Base
has_many :houses
end
class House < ActiveRecord::Base
belongs_to :court
end
Note: This is not functional. Do not just copy paste it. Instead, read this: http://guides.rubyonrails.org/association_basics.html
I assume you are not just new to Rails, but also web dev. If that is the case, you might be in over your head. You are doing some fairly advanced Rails stuff.

Selecting belongs_to parents in a form?

Imagine I have something like this:
class Employer < ActiveRecord::Base
has_many :employees
end
class Employee < ActiveRecord::Base
belongs_to :employer
end
And I want to create a new Employee, and give a form with with a drop down box, where I can select which Employer I wish to associate it with. The dropdown should list every employer in the system. How can I do this?
Thanks.
I think you haven't understood what this association does. Or I haven't understood what you really want.
If you want to display ALL employers in a view, you simply have to fetch them in the corresponding controller action and save it in an instance variable. Then you can access its contents inside the view.
controller action:
#employers = Employer.all
...
corresponding view:
<%= collection_select #employers %>

Ruby on Rails Relationships for Two Models

I have two different models.
Item Model
class Item < ActiveRecord::Base
belongs_to :category
attr_accessible :make, :model, :name, :purchasedfrom, :qrcode, :serialnumber, :category_id
end
Event Model
class Event < ActiveRecord::Base
belongs_to :category
attr_accessible :name, :location_id, :category_id
end
I cannot figure out how to do the following:
An Event has multiple Item that can be at the Event.
An Event history still shows Items from a particular event.
Would show items from event: localhost/event/:id/items
I cannot figure out this for the life of me. If I can get some direction in this issue, I would greatly appreciate it! Thanks in advance for all of your help.
I have seen the use of :through which I believe I would have to use here.
If I understood your question correctly, here you can write something like this in Event model.
class Event
def items
category.items
end
end
then in controller,
#event = Event.find(params[:id])
#items = #event.try(:items)
I think that what you would want to do is:
class Item < ActiveRecord::Base
belongs_to :event
end
and for Events:
class Event < ActiveRecord::Base
has_many :items
end
Then you should be able to view the items for an event by calling:
#event = Event.find_by_id(:id)
#event.items.all
If one Category can have many Events I think you must add event_id in Item to be able to know exactly what Items that has been on exactly one Event.
(And in that case add relations for that).
Or join table between Event and Item and has_and_belongs_to_many if one Item can be on many Events
EDIT:
If it's like that, add table events_items, relation has_and_belongs_to_many :items (in Event and :events in Item), and read documentation for has_and_belongs_to_many.
Otherwise, if you are looking for Items that has been on a certain Event you will find all Items that have been on all Events that has the same Category as the Event you are investigating.

How to associate existing model with new model in Rails

I have a 'tip' model and a 'team' model. I am trying to create a form where a user will select the winning teams from several games. So far the user can select the winning teams and those id's are being saved as foriegn keys in the Tip model (team_id). But after saving, I can't go (for example ) #tip.team.name . What do I need to do ? How do I associate it (I though rails might magically do it if foriegn key is set), I am very new to rails. Thanks for any help !
class Tip < ActiveRecord::Base
attr_accessible :user_id, :team_id, :team, :game_id, :game, :comp, :comp_id
belongs_to :game
belongs_to :comp
belongs_to :team
end
class Team < ActiveRecord::Base
attr_accessible :name
has_many :tips
end
def create
params['game'][0].each do |key, value|
#tip = Tip.new
#tip.team_id = value
#tip.game_id = key
#tip.save
end
This last method may be messy too, but not sure how else to do it. There are several 'tips' that I want to create in the one form.
EDIT : To be clear I am quite sure it's a one to many relationship, I am creating several tips in the one form but each tip only relates to one team.
EDIT : Actually my approach (which I'm sure is not close to the best way, did allow tip.team.name. It was a silly error relating to my test data that made me think otherwise.
What you really need is to use a has_many through relation to link the tips and the teams. This is because one tip can have many teams, but also one team can be on many tips. You will need to create a third table to do this, maybe named TeamsTips. Here is how you might set it up:
class Tip < ActiveRecord::Base
has_many :teams_tip
has_many :teams, :through => :teams_tip
end
class TeamsTip < ActiveRecord::Base
belongs_to: teams
belongs_to: tips
end
class Team < ActiveRecord::Base
has_many :teams_tip
has_many :tips, :through => :teams_tip
end
Now when you have a #tip, you can find all the teams for it with #tip.teams. Remember, this will be an array so to get the first team use #tip.teams[0]. Likewise, if you have an #team, you can get all the tips for it with #team.tips.
For more informations on how to setup this has_many through association, see A Guide to Active Record Associations
if ur asscociation is "Tip belongs to a Team " and "Team can have many Tips" then the association u defined in the question is correct.
if u want to created multiple tips when a team is created or add/edit/delete tips for a already created team, have a look at "accepts_nested_attributes_for" and https://github.com/ryanb/nested_form.
If u can get the team name using '#team.name' then u should get it using "#tip.team.name"

Rails - Create/Destroy record in join table

I'm working on this record insert/delete I'm not sure what the syntax is to perform the query.
I have a user model and an event model. I have created a joining table called Personal that stores the user_id, and event_id of any events that the users like.
I created an "Add" method in my events controller so whenever someone clicks it run to that and perform the create logic I'm trying to develop now.The action is tied to a extra column I added to the grid displaying all the events.
The user model =>
has_many :personals
The event model =>
has_many :personals
The personal model =>
belongs_to :user
belongs_to :events
I thought it would be something like =>
#user = User.find(session[:user_id])
#event = Event.find(params[:id])
# Personal.new = User.Event?
can anyone help?
If you're using a has_and_belongs_to_many association, which would be unfortunate, removing the associated links can be tricky as there's no identifier for each link.
Using a has_many :through relationship is much easier to maintain and will allow you to do simple things like:
class User < ActiveRecord::Base
has_many :user_events
has_many :events,
:through => :user_events
end
#user.events.delete(#event)
This doesn't remove the Event itself, that'd require an Event#destroy call, but the join record that links the two.

Resources