find_or_create on a has many through relationship - ruby-on-rails

I have a has many through relationship in my app:
Shows has many Bands through => Lineups
Bands are unique by :name
class Show < ActiveRecord::Base
attr_accessible :city_id, :title, :dateonly, :timeonly, :image, :canceled, :venue_attributes, :bands_attributes
belongs_to :city
belongs_to :venue
has_many :lineups
has_many :bands, through: :lineups
has_and_belongs_to_many :users
end
class Lineup < ActiveRecord::Base
belongs_to :show
belongs_to :band
end
class Band < ActiveRecord::Base
attr_accessible :name, :website, :country, :state
has_many :lineups
has_many :shows, through: :lineups
validates :name, presence: true
validates_uniqueness_of :name
before_save :titleize_name
private
def titleize_name
self.name = self.name.titleize
end
end
New Bands are created like this:
(lets say we have a show record already saved called s1)
> s1.bands.new(name: "Wet Food")
> s1.save
Right now this will only save if a band named "Wet Food" doesn't already exist
In which model is the best place to do a Band.find_or_create in this relationship so that an existing band can be used if one with the same name exists?

This is generally the type of call that would go in a Controller (or maybe a service object), but not in a Model. It really depends on the particular user flow that you're trying to accomplish in your app. Basically, where ever you are already using s1.bands.new, you could use this instead :
s1.bands.where(name: 'Wet Food').first_or_create

Related

Rails relationship between three models confusing

I know there is a plenty of tutorials explaining how to create a 'has_many through' relationship between models, but I think my question is both technical and conceptual.
The objective is to create an online food ordering website
I created the Order, Item and OrderItem models.
Relationships:
class OrderItem < ActiveRecord::Base
belongs_to :item, conditions: "active = true"
belongs_to :order
end
class Order < ActiveRecord::Base
belongs_to :user
has_many :order_items
has_many :items, through: :order_items
validates :status, inclusion: { in: %w(ordered completed cancelled) }
end
class Item < ActiveRecord::Base
has_and_belongs_to_many :categories, join_table: :items_categories
has_many :order_items
has_many :orders, through: :order_items
validates_presence_of :title, :description
validates :price, numericality: { :greater_than=>0 }
end
Am I doing something wrong? Each order should be able to contain many items and the quantity of them.
I'm not very positive I'm doing the correct architecture for these models, as I can't assign the quantity via << operator, only assign the item.
Thanks for your time.
like this
order = Order.new(user: #user)
order.order_items << OrderItem.new(quantity: 100, item: Item.first)

An equivalent to first_or_create on a nested attribute in Rails 4

I'm using a has many through pattern with these 3 models
class User < ActiveRecord::Base
has_many :user_topics
has_many :topics, through: :user_topics
end
class Topic < ActiveRecord::Base
validates_presence_of :name
validates :name, :uniqueness => true
end
class UserTopic < ActiveRecord::Base
belongs_to :user
belongs_to :topic
accepts_nested_attributes_for :topic
end
At the moment a new topic model is trying to be created every time a new user_topic is created. I'd like to create a new topic model only if the topic name doesn't already exist, otherwise if it does, use the existing topic_id.
So something like:
class UserTopic < ActiveRecord::Base
belongs_to :user
belongs_to :topic
accepts_nested_attributes_for :topic, :first_or_create(:name)
end
Is it possible to do something similar to this?

Buid two associations between two tables

I have a strange requirement in my project. Actually, I have two tables (users,galleries). I would like to access galleries table with has_one as well as has_many associations. The main purpose is to get the profile snap of the user by using has_one relation and to get the personally uploaded pictures by using has_many relation.
Initially I go with polymorphic association to resolve this (FYI, please find the below code snippet) .But I think it is not the right approach for this problem.
Would anybody explain how to handle this case in an efficient way.
class User < ActiveRecord::Base
attr_accessible :name
has_many :galaries, as: :imageable
has_one :galary, as: :imageable
end
class Galary < ActiveRecord::Base
attr_accessible :name
belongs_to :imageable, polymorphic: true
end
You need to add a column user_id in galaries table in order to link the the user to the galary (profile snap).
rails generate migration add_user_id_to_galaries user_id:string
This will generate the migration:
class AddUserIdToGalaries < ActiveRecord::Migration
def change
add_column :galaries, :user_id, :integer
end
end
Then run rake db:migrate
Moving to our Models now:
class User < ActiveRecord::Base
attr_accessible :name
has_many :galaries, as: :imageable
has_one :galary #profile snap
end
class Galary < ActiveRecord::Base
attr_accessible :name
belongs_to :imageable, polymorphic: true
belongs_to :user #profile snap user
end
Can be done with scoped has_one association. Although not necessary, you can define which gallery is selected in the has_one using a scope. If no scope is given, the has_one would return the first match.
class User < ActiveRecord::Base
attr_accessible :name
has_many :gallaries
has_one :gallery, -> { where primary: true }
end
class Gallery < ActiveRecord::Base
#user_id, primary (boolean variable to select the gallery in has one association)
attr_accessible :name
belongs_to :user
end

creating object with nested attributes

i need to create a form, which will create object which has another two objects as attributes, but those objects should be available from a dropdown list that contains templates of those objects.
class User < ActiveRecord::Base
accepts_nested_attributes_for :adresses, :profiles
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
tricky part might be, that User has no column 'address_id' or 'profiles_id', everything should go to the Profile and Address, which are being created in the same moment as the User (they have the same attributes as their templates)
I could really use some help, dont expext full code solution, but some hints would be nice
Try this setup:
class User < ActiveRecord::Base
has_one :address
has_one :profile
accepts_nested_attributes_for :address, :profile
attr_accessible :adress_attributes, :profile_attributes
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
See doc

has_and_belongs_to_many and has_many_through on same model

Is it acceptable to have a has_and_belongs_to_many: association as well as a has_many through: relationship on models? For instance, I have three models, Facility, Athlete, and Event.
An Athlete has and belongs to many Facilities, and vice versa. I need to allow for Facilities to create Events that belong to both the facility and the athlete. So I have the following.
class Athlete < ActiveRecord::Base
attr_accessible :age, :email, :facility_id, :name
has_and_belongs_to_many :facilities
has_many :events
has_many :facilities, :through => :events
end
class Facility < ActiveRecord::Base
attr_accessible :name, :contact_email, :contact_name, :telephone
has_and_belongs_to_many :athletes
has_many :events
has_many :athletes, :through => :events
end
class Event < ActiveRecord::Base
attr_accessible :athlete_id, :facility_id, :rfd250, :rfd50, :rfd85
belongs_to :athlete
belongs_to :facility
end
My hope with this setup is that from Facilities#Show, I can create new Athletes associated with a particular Facility (athletes_facilities table). After which I can display only those athletes associated with the Facility, and create new Events for them.
Is this the wrong way to approach the problem?

Resources