has_many with two or more tables. - ruby

I'm trying to add multiple has_many relationships to my model:
class Program < ActiveRecord::Base
has_many :courses, :program_offers
belongs_to :university
attr_accessible :end_date, :name, :period, :start_date, :symbol, :year, :university_id, :description, :titles, :profile, :price
end
But I get:
hash expected error.
How can I reference two has many tables?

You can't do that because it is association method which takes only one association name as argument:
has_many(name, options = {}, &extension)
So specify each association in single line.
has_many :courses
has_many :program_offers
If you specify like that it considers that you are specifying some condition or block. See the API doc http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many

Related

How to get the association name in rails?

I have the following association code in my user.rb model file
class User < ActiveRecord::Base
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id'
has_many :received_messages, class_name: 'ChatMessage', foreign_key: 'receiver_id'
end
I want a method in the ChatMessage model which should be triggered by the following
current_user.sent_messages
current_user.received_messages
The method should return the name of the association that was called.
Eg:
class ChatMessage < ActiveRecord::Base
after_find :get_association_name
def get_association_name
self.association_name // this should return sent_message or received_message depending on whether current_user.sent_messages or current_user.received_messages was called
end
end
Is there a way to get this association name in rails?
Any help is much appreciated. Thanks
I am not sure, exactly what you are looking for, but
CurrentUser.reflect_on_all_associations(:has_many)
will give an array of all has_many associations.
I haven't used AR associations extensions for cases like this, but you should be able to do:
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id' do
def get_association_name; 'sent_messages'; end
# or, to make this more generic,
# def get_association_name; proxy_association.reflection.name.to_s; end
end
And the method should be accessible from your relation. If you were using Rails 4, you could extract the generic version out into a separate module to extend your associations more succinctly. See http://guides.rubyonrails.org/association_basics.html#association-extensions.
EDIT
Try:
has_many :sent_messages, class_name: 'ChatMessage', foreign_key: 'sender_id' do
def and_set_type
proxy_association.target.each do |msg|
msg.update_attribute(:type, 'sent')
end
scoped
end
end
And then access your sent_messages with current_user.sent_messages.and_set_type.

Has_many through form

I am hoping for some help with constructing a form a has_many :through relationship.
I have three classes:
order.rb
has_many :selections
has_many :items, :through =>:selections;
item.rb
has_many :selections
has_many :orders, :through => :selections
selection.rb
belongs_to :order
belongs_to :item
Selections has an extra property on it to capture the quantity of the selected item.
What I'm trying to do is create a form that allows a user check a box indicating the type of item they want and supply a quantity.
_X_ Food1 _6_
___ Food2 __
_X_ Food3 _1_
My problem is that I don't have any idea how to name the form elements so that they make it into the controller. I can't use
<%= collection_check_boxes(:order, :item_ids, #course.items.all, :id, :name, {:item_wrapper_class => 'checkbox_container'}) %>
because that will just print the food with checkboxes and I need to capture the quantity for each selected item.
What I could use help with is how to create the _form.html.erb as well as special gotcha's that I might need to have in my controller.
First off, item.rb should read,
has_many :selections
has_many :orders, :through => :selections
Secondly, why are you using a check box? Why not just forms that if empty default to zero or nil? That is, if you have more than one, you can use it as a truthy value in lieu of a check being checked or not.

How can I do a LIKE query using an association?

Using ActiveRecord, how can I do a LIKE query based on a property of an association? Specifically, I'm looking for something that works with polymorphic associations.
class Invoice < ActiveRecord::Base
has_one :private_note, class_name: '::Note', as: :noteable,
conditions: {label: 'private'}
has_one :public_note, class_name: '::Note', as: :noteable,
conditions: {label: 'public'}
end
class Note < ActiveRecord::Base
belongs_to :noteable, polymorphic: true
validates :content, :presence: true
end
I want to find invoices whose private_note has a content column containing the word "friendly".
Use #merge
This can be accomplished with the .merge method.
Invoice.joins(:private_note).merge(Note.where("content LIKE ?", '%friendly%'))

ActiveRecord::HasManyThroughAssociationPolymorphicSourceError

I need a player to have many structures and the structure to belong to the player. Structure is a polymorphic relationship.
class Player < ActiveRecord::Base
has_many :player_structures
has_many :structures, :through => player_structures
end
class PlayerStructures < ActiveRecord::Base
belongs_to :structure, polymorphic: true
belongs_to :player
end
class StructureA < ActiveRecord::Base
has_one :player_structure, :as => :structure
has_one :player, :through => :player_structure
end
class StructureB < ActiveRecord::Base
has_one :player_structure, :as => :structure
has_one :player, :through => :player_structure
end
But if I pull out Player.first and ask for its structures, it gives:
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'Player#structures' on the polymorphic object 'Structure#structure'.
But it should be able to generate a SQL query where it finds all player_structures with its id, then fetches the structure based on the structure_id and structure_type. Why does this fail and how can I validly construct a polymorphic join table?
UPDATE
If I do what I want it to do manually, it works:
player_structures.collect(&:structure)
Rails, y u no do that?
I think you need to be more specific in defining your relationships in your Player model. For example:
class Player < ActiveRecord::Base
has_many :player_structures
has_many :structureas, :through => player_structures, :source => :structure, :source_type => 'StructureA'
has_many :structurebs, :through => player_structures, :source => :structure, :source_type => 'StructureB'
end
Then you can make a method that'll return all the structures defined in the relationships instead of having to access each one individually.

ActiveRecord: Has many through (twice)

There are Things in Places which I'm looking to find. One Thing could be in many different Places, and many Things can be in one Place.
class Thing < ActiveRecord::Base
has_and_belongs_to_many :places
end
class Place < ActiveRecord::Base
has_and_belongs_to_many :things
end
I want to record the Finds of my Users so that I know where they found what.
class Find < ActiveRecord::Base
belongs_to :user
belongs_to :places_thing # Is this depluralization correct?
end
class User < ActiveRecord::Base
has_many :finds
# Now, how can I link in the Things the user has found? Like this?
has_many :found_things_in_places, :class_name => :places_things, :through => :finds
has_many :things, :through => :thought_things_in_places
end
Does this seem right? is it efficient? Thanks.
I think you were on the right track, the big change I'd make is that rather than having a join table (places_things) you should make it a proper model. I decided to call this an existence.
The data only exists in one place, so it's properly normalized. These relationships are clear and will be easy to manage. I think it's efficient.
class Place < ActiveRecord::Base
has_many :existences
has_many :things, :through => :existences
end
class Thing < ActiveRecord::Base
has_many :existences
has_many :places, :through => :existences
end
class Existence < ActiveRecord::Base
belongs_to :place
belongs_to :thing
end
class Find < ActiveRecord::Base
belongs_to :user
belongs_to :existence
end
class User < ActiveRecord::Base
has_many :finds
has_many :existences, :through => :finds
has_many :things, :through => :existences
end
You'll need rails 3.1 to do the nested has many through's like we did in User.
BTW the correct association declaration should be: belongs_to :places_things

Resources