Ruby on Rails Relationships for Two Models - ruby-on-rails

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.

Related

Array not saving from one model to another in rails

I am trying to save an array of multiple ids (item_variation_ids) to a model called items_stock from item variations model. In a column called item_variation_ids in item_stock, it is saving the ids like [1,2,3] for twice. I want the item_variation_ids to be saved once only with 1,2,3 in a single column.
My item_variation model
#app/models/item_variation
class ItemVariation < ApplicationRecord
belongs_to :item
validates_associated :item
after_save :add_to_item_stock
def add_to_item_stock
ItemStock.create(item_variation_ids: ItemVariation.ids, items_id: items_id)
end
end
My item model
#app/models/item
class Item < ApplicationRecord
has_many :item_variations, foreign_key: :items_id
has_many :item_stocks, foreign_key: :items_id
accepts_nested_attributes_for :item_stocks
end
My item_stock model
#app/models/item_stock
class ItemStock < ApplicationRecord
belongs_to :item
end
But how do you know which ItemVariation ids should go on that ItemStock? and you are creating one ItemStock each time any variation gets saved. I don't even think you need to set that ids array since the ItemStock already belongs to an Item which has many variations (#item_stock.item.variations and you are done).
Also now you are talking about a stock_qty attribute you never mentioned before, you are never setting it on the callback and you didn't show your database schema. where does that amout come from? is an attribute on the variation that you want to sum to the current item_stock?
I also don't understand why an item has many item stocks for the code you are showing.
I'll do a wild guess and suggest you do something like:
ItemStock
belongs_to :item
belongs_to :item_variation
end
ItemVariation
after_save :add_to_item_stock
def add_to_item_stock
item_stock = self.item.item_stock.where(item_variation_id: self.id).first_or_initialize
item_stock.stock_qty = self.stock_qty
item_stock.save
end
end
but as I said, it's a wiiiiild guess. I'd recommend you to first try to understand what you are doing, because it seems like you just copied to code from that question you linked and you are no actually understanding it.

rails joining two tables together using has oen and has many

So I'm trying to link two models together
currently, I have tickets for events.
in the event model, I'm under the understanding that one event has one or more tickets so that would be a has many?
and in the tickets table, it would have one event?
In the tickets table, I have the event_id column.
Basically what I've wanting to have is the ability to type event.tickets.each for example to return all the tickets in the event
event.rb model
class Event < ActiveRecord::Base
has_many :tickets
end
ticket.rb model
class Ticket < ActiveRecord::Base
belongs_to :event
end
to fetch tickets of event do like below
event = Event.first
event.tickets.each do |ticket|
puts ticket.inspect
end
in ticket model add has_many :events
in event model add belongs_to :ticket
your events table should have a ticket_id foreign key.
this way you can do event.ticket
and also ticket.events
that is all :)

Many to Many relation issue in Rails 4

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.

Rails Multiple Parent Relationships

Three models:
User
List
Item
A User can have many Lists and a List can have many Items. Each List can have an Item added to it by ANY User. This means, for example, that you can create a list and I can add items to it. Make sense? Let's keep going.
I want to be able to find all Items created by X User at any point in time.
class User < ActiveRecord::Base
has_many :lists
has_many :items
end
class List < ActiveRecord::Base
belongs_to :user
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :list
belongs_to :user
end
I don't like this. It has a funky smell but I can't put my finger on it. I feel like there should be something better. When creating a new Item I would have to write something that looks like the following:
list = List.find(params[:list_id])
#item = list.items.new(params[:item])
user = User.first
#item.user = user
#item.save!
So, what am I missing? Are my relationships wrong (very likely)? Tell me! :)
It seems like there can be two different relationships between items and users: 1) items are added to lists by users, and 2) lists are created by users.
Only one user can create a list. Many users can add items to lists after they are created.
So modeling this requires two different relationships
class User < ActiveRecord::Base
has_many :lists
has_many :items_added, :class_name => "Item", :foreign_key => "added_by_user_id"
end
class List < ActiveRecord::Base
belongs_to :user
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :list
belongs_to :added_by_user, :class_name => "User", :foreign_key => "user_id"
end
It makes sense to assume that you all these relationships are required -- that is, a list needs a user_id when it's created to show who created it. Likewise, an item needs to record who added it to the list.
You'd need to add the added_by_user_id column to your items table to make this work and keep track of which user added the item.
So you could do this:
# To create a user and a list is easy!
user = User.create(user_params)
list = user.create_list(list_params)
# but when adding an item, you need to know which user is adding it
item = list.create_item({:added_by_user => current_user, :item_name => 'name', etc})
Now you can find all items added by a user using:
all_user_items = user.items_added
I haven't tested this and it's a bit complicated so I may have 1-2 mistakes in the code, but generally that's one way this could be modeled.

Lists items order when items can be on multiple lists (ruby on rails)

So I have a rails app That lets users create lists and put items on that list. As a feature a user can put any one item on multiple lists. Example:
List_1
-item_1
-item_2
List_2
-item_3
-item_2
The relationship side of it all is complete and working fine.
The next step was to let the user arrange the items in their lists. I installed act_as_list and using jQuery sortable got a simple drag and drop working for sorting items. The issue is each item has one position. So if I change item_2's position to 1 on list_1, item_2's position is now 1 in every list.
I'm trying to think of a way to store item positions relative to the list. Anyone have any thoughts?
Edit to Add code
List model
class List < ActiveRecord::Base
belongs_to :user
has_many :assignments, dependent: :destroy
has_many :items, through: :assignments, order: 'position'
end
Item model
class Item < ActiveRecord::Base
belongs_to :user
has_many :assignments, dependent: :destroy
has_many :lists, through: :assignments
acts_as_list scope: :list
end
Assignment model
class Assignment < ActiveRecord::Base
belongs_to :item
belongs_to :list
validates_uniqueness_of :item_id, :scope => :list_id
end
So an answered my own question with a little time an effort. I've provided an example below for anyone who may run into the issue in the future.
Basically #thedeeno's answer would have worked fine if I was able to use scopes. In my case the list will be user created and hence scopes are not an option.
Solution:
So my solution was adding a position column to my assignments table (the join table for my has many through)
This way each assignment could now have a list_id and item_id and a position.
Then in my controller I did the following to populate the #items hash
#items = #list.items.order(:position)
This gave makes #item has ordered by item positions for their respective list position.
Now the last step was updating their position using sortable. To update the correct item's postion I needed sortable to send the list_id along with each order of the id's. To get the list_id sent with the post I adding a hidden li with and id of the #list like so
<li id='list_<%=#list.id %> style='display:none'></li>
which meant that my params now looked like this
{"list"=>["31"], "item"=>["30", "58", "59", "24", "80", "81"]}
Finally using the skills I had learned from http://railscasts.com/episodes/147-sortable-lists I changed my sort action to the following
def sort
#items = params[:item]
#items.each_with_index do |id, index|
assignment = Assignment.where(list_id: params[:list], item_id: id).update_all(['position=?', index+1])
end
render :nothing => true
end
That's it! users can now create any number of lists and item to multiple lists and sort each list independently. Hope this helps someone!
You can promote these 'lists' to a formal model and then scope acts_as_list position to that model. Similar to the example from the docs:
class List < ActiveRecord::Base
has_many :items, :order => "position"
end
class Item < ActiveRecord::Base
belongs_to :list
acts_as_list :scope => :list
end
The point of scoping is to make the position relative to another model. You can also have multiple positions scoped to multiple models.
EDIT:
If multiple scopes is your issue, you might want to checkout the sortable gem.

Resources