Rails relationship based on common field - ruby-on-rails

I've found quite a few topics on ActiveRecord has_many relationships, but I haven't found exactly what I am looking for.
I've got two tables that each have the column xyz_id. This id is a corresponding ID in an API service I'm subscribed to.
I want to have a has_many relationship through these corresponding ids in the corresponding columns on each table. Such that, if an item in table_1 has an xyz_id of "abcdefg", I can do something like table_1.relation and it will return all elements in table_2 with a matching xyz_id. I could leverage ActiveRecord throughout my code and utilize queries, but I think there has to be a better way. Any thoughts?
EDIT: I a word.

ActiveRecord lets you specify arbitrary fkeys when you define the relationship, like so:
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts,
foreign_key: :xyz_id
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies,
foreign_key: :xyz_id
end
Source: http://guides.rubyonrails.org/association_basics.html

Related

In Rails: how do I create a many-to-many relationship where both models have teh join key?

I have models A and B. Both have the magic column. If a record a from A and a b from B have the same magic, then they are related. Many records from A and B may have the same magic.
Is there a way to express this belongs_to_many sort of thing in my Rails models? How?
There's a high value in following the Rails way, and what you're trying to do isn't the standard way of doing this.
The Rails Way: You should create a has-and-belongs-to-many relationship using an intermediate model and table, as described in the Rails Guides website.
But if you insist...: Try this:
# model_a.rb
class ModelA < ActiveRecord::Base
has_many :model_bs, class_name: 'ModelB',
foreign_key: :magic,
primary_key: :magic
end
# model_b.rb
class ModelB < ActiveRecord::Base
has_many :model_as, class_name: 'ModelA',
foreign_key: :magic,
primary_key: :magic
end
I haven't tested this, but I am fairly certain that it would work.
Final words... Don't do it! Follow the Rails way. :)

Rails 4 and referencing parent id in 'has_many' SQL

TL;DR: How do I use the ID of the respective parent object in a has_many SQL clause to find child objects?
Long version:
I have the following example code:
class Person < AR::Base
has_many :purchases, -> {
"SELECT * from purchases
WHERE purchase.seller_id = #{id}
OR purchase.buyer_id = #{id}"
}
This was migrated from Rails 3 which worked and looked like
has_many :purchases, :finder_sql => proc { #same SQL as above# }
I want to find all purchases associated with a Person object in one association, no matter whether the person was the one selling the object or buying it.
Update: I corrected the SQL, it was inside out. Sorry! Also: The association only needs to be read-only: I am never going to create records using this association, so using id twice should be OK. But I do want to be able to chain other scopes on it, e.g. #person.purchases.paid.last_5, so creating the sum of two associations in a method does not work (at least it didn't in Rails 3) since it doesn't return an AM::Relation but a simple Array.
When using this above definition in Rails 4.2, I get
> Person.first.purchases
undefined method `id' for #<Person::ActiveRecord_Relation:0x...>
The error is clear, but then how do I solve the problem?
Since this is only an example for much more complicated SQL code being used to express has_many relationships (e.g. multiple JOINS with subselects for performance), the question is:
How do I use the ID of the parent object in a has_many SQL clause?
I don't think your code will work at all. You are defining an association with two foreign keys ... that'd mean that in case you want to create a new Person from a present Purchase, what foreign key is to be used, seller_id or buyer_id? That just don't make sense.
In any case, the error you are getting is clear: you are calling a variable id which is not initialized in the block context of the SQL code.
A better approach to the problem I understand from your question would be to use associations in the following way, and then define a method that gives you all the persons, both buyers and sellers that a product has. Something like this:
class Purchase < ActiveRecord::Base
belongs_to :buyer, class_name: 'Person'
belongs_to :seller, class_name: 'Person'
def persons
ids = (buyer_ids + seller_ids).uniq
Person.where(ids: id)
end
end
class Person < ActiveRecord::Base
has_many :sold_purchases, class_name: 'Purchase', foreign_key: 'buyer_id'
has_many :buyed_purchases, class_name: 'Purchase', foreign_key: 'seller_id'
end
Im my approach, buyer_id and seller_id are purchase's attributes, not person's.
I may have not understood correctly, in that case please clarify.

ActiveRecord two way foreign key.

I'm using some open gov data in MYSQL which I've imported into my rails App.
I've extended the database with some of my own tables, and use the rails provided column ids in my tables.
However, the tables of the original database are linked through a unique 'ndb' id.
I thought that by cross-referencing two :foreign_key=>'ndb' between the models I would get the tables linked properly, but through :foreign_key, it appears to be linking the id from one table to the ndb column of another.
My models look like this
class Food < ActiveRecord::Base
has_many :weights, :foreign_key=>'ndb'
has_many :food_names
end
class Weight < ActiveRecord::Base
belongs_to :food, :foreign_key=>'ndb'
Is there a way to specify that the 'ndb' column is the link between the food and weights table, and not the food_id to ndb?
Have you tried set_primary_key 'ndb' in your AR classes?
set_primary_key docs.
What I've done as a possibly temporary solution, is to used the :finder_sql to link the tables together.
My Food model now has:
class Food < ActiveRecord::Base
has_many :weights, :finder_sql =>'Select weights.* FROM weights LEFT JOIN foods ON foods.ndb=weights.ndb WHERE foods.id=#{id}'
I'm not sure if this is the best solution or not, but it seems to be working.

What is the relationship between these two tables in RoR?

I am developing an application like the stackoverflow, which questions or articles have at less one tag. And one tags must have one or more articles.
So, I am doing this in migration in RoR. I am consider which relationship is suitable for both table. In article table, should use a "has_many", and in the tag table, should use "has_many".
But I am thinking is it necessary to add one more table in the middle, something like....
So, the first one is like that:
class Article < ActiveRecord::Base
has_many :tags
end
class Tag < ActiveRecord::Base
has_many :articles
end
or something like this:
class Article < ActiveRecord::Base
has_many :articleTagList
has_many :tags, :through => : articleTagLists
end
class Tag < ActiveRecord::Base
has_many :articleTagList
has_many :articles, :through => :articleTagLists
end
class ArticleTagList < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
Many-to-Many relationships in a normalized database will always need a third "look-up table."
If you denormalize you can get away with just having the tag id's in one field with a delimiter between them. But you also have to provide the logic to handle retrieval.
I'd personally just go with the normalized option.
If you don't want to store any information on the middle table (for example the name of the user who added tag X to the question Y), you can use the has_and_belongs_to_many:
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many
If you want to store something, you need to create the middle model, as your example. In your example, the ArticleTagList model should be called ArticlesTag and the database table should be articles_tags, by convention.

RoR: "belongs_to_many"? Association headache

I can't seem to wrap my head around this, so I thought I'd post and see if anyone could help me out (please pardon the question if it's insultingly simple: it's complicated to me right now!)
I have these models:
order
service
customer
I think they speak for themselves: a service is what the customer buys when they place an order.
Ok.
So, naturally, I setup these relationships:
# a customer can have many orders
class Customer
has_many :orders
end
# an order belongs to a single customer and can have many services
class Order
belongs_to :customer
has_many :services
end
... but here's where I trip up:
# a service can belong to many orders
class Service
# belongs_to :order ???
end
Because my understanding of belongs_to is that--if I put it there--a service could only belong to one order (it would have only one value in the order_id key field--currently not present--tying it to only one order, where it needs to be able to belong to many orders).
What am I missing here?
There are two ways to handle this. The first is a rails-managed many-to-many relationship. In this case, you use a "has_and_belongs_to_many" relationship in both the Order and Service models. Rails will automatically create a join table which manages the relationships. The relationships look like this:
class Order
has_and_belongs_to_many :services
end
class Service
has_and_belongs_to_many :orders
end
The second way is to manage the join table yourself through an intermediate model. In this case, you might have another model called "LineItem" that represents a Service in the context of an Order. The relationships look like this:
class LineItem
belongs_to :order
belongs_to :service
end
class Order
has_many :line_items
end
class Service
has_many :line_items
end
I prefer the second myself. It's probably just me, but I don't get as confused about what's going on when it's explicit. Plus if I ever want to add some attributes to the relationship itself (like perhaps a quantity in your case) I'm already prepared to do that.
class Customer
has_many :orders
end
class Service
has_many :orders
end
class Order
belongs_to :customer
belongs_to :service
end
The Order should have customer_id and service_id, because it is in a many-to-one relationship with both.
I think this Railscast will help you out - basically you have 2 options. You can use has_and_belongs_to_many or has_many :through.
You will also find that has_and_belongs_to_many has been deprecated in favor of has_many :though => model_name which gives the same (and more) functionality.
I think you have realized this but your order is really a composite domain model, sometimes called an aggregate in DDD speak.
Your Service is a really a listing of some product/service that someone can order. Your order aggregate records what someone ordered.
The aggregate as someone else said is made up of a header, the Order, which includes things like who ordered, the date, does it include taxes, shipping charge, etc. And the Order has_many OrderLineItem's. The OrderLineItem belongs_to Service and contains things like the quantity ordered, belongs_to the product/service, etc.
class Customer < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :customer
end
class OrderLineItem < ActiveRecord::Base
belongs_to :Order
end
I personally use the OrderLineItem model name in deference to LineItem because in a system that needs to ship real products, as opposed to services, you might have allocations that link orders to inventory which would have line items and shipments that get the allocated product to the client, which also have line items. So the line item term can become very overloaded. This likely is not the case in your model because you're only doing services.

Resources