I have the follow set up in my models:
class Project < ApplicationRecord
has_many :plans
end
class Plan < ApplicationRecord
belongs_to :project
has_many :documents
end
class Document < ApplicationRecord
belongs_to :plan
end
I'm trying to make a query in which I can easily return all nested associated records. For example, I want to be able to do something like: Project.documents and get all documents for a project. I've tried this with an includes like so:
Project.includes({plans: [:documents]})
but that doesn't appear to give me what I want when I call Project.documents. I really only want all documents for a project, so don't really need to include plans. Is there an easy way todo this in Rails 6?
The relationship between a document and a plan goes first through project, so you can use joins, specifying that a document belongs to a plan, and that a plan belongs to a project. After that you can filter the rows by selecting the plans (whose document belongs to) having the project_id equals ...:
Document.joins(plan: :project).where(plans: { project_id: ... })
Related
I have a HMT relationship between tab_projects, tab_proj_platforms, and ref_platforms. In my tab_projects.index() I wrote this assignment:
#tab_projects = TabProject.includes(:ref_platforms)
And I want to return a list of projects along with their associated platforms. The SQL generated was correct and I validated it directly in the database. The record results contained columns from both tab_projects and ref_platforms, which was what I wanted. However my results in #tab_projects only contained the columns in TabProject and nothing from RefPlatform.
I was perusing for potential solutions and it seemed like what I found simply would iterate the collection of #tab_projects.ref_platforms, but I am returning everything as a JSON document so I want to collect everything at runtime.
Just in case my model associations contain some bug I've included them below:
tab_project.rb:
class TabProject < ApplicationRecord
has_many :tab_proj_platforms
has_many :ref_platforms, through: :tab_proj_platforms
end
tab_proj_platform.rb:
class TabProjPlatform < ApplicationRecord
belongs_to :tab_project
belongs_to :ref_platform
end
ref_platform.rb:
class RefPlatform < ApplicationRecord
has_many :tab_proj_platforms
has_many :tab_projects, through: :tab_proj_platforms
end
How can I save projects and their associated platforms into #tab_projects so I can dump them into a JSON document?
inside tab_project.rb: create scope as follow
scope :project_and_platform, lambda { |id_tab_project|
joins(tab_proj_platform: :ref_platform).select('ref_platforms.*','tab_projects.*').
where("tab_projects.id = ?", id_tab_project)
}
from your TabProject controller, you can access scope as follow
#tab_project_with_platforms = TabProject.project_and_platform(params[:id])
So I want my User model to have_many Skills. I want there to be two different categories for the skills: a wanted skill, and a possessed skill.
For example, a user can add a skill to their profile that they possess, such as HTML. They can also add a skill to their profile that they wish to learn, such as Ruby on Rails. On their profile it'll list their current skills and wanted ones, separately.
From a high level, what's the best way to architect this? I just want there to be 1 Skill model with no duplicates, but I want there to be a way for users to have the 2 separate groups of skills in the database.
You can use single table inheritance
class Skill < ActiveRecord::Base
end
class WantedSkill < Skill
belongs_to :user
end
class PossessesSkill < Skill
belongs_to :user
end
Your skills table should have a column called type where the type of the skill will be stored.
WantedSkill.create(:name => "html")
Above will save the record in the skills table with type 'WantedSkill'. You can retrieve it by
WantedSkill.where(:name => "html").first
your user associations can be like
class User < ActiveRecord::Base
has_many :wanted_skills
has_many :possessed_skills
end
You can read documentation here
A way to achieve this, you need two skill fields like: wanted_skill and possessed_skill
So, in Ruby on Rails you can have many references (with different names) to the same model, you only need to declare which class corresponds using class_name in the references, e.g.:
class User < ActiveRecord::Base
belongs_to :wanted_skill, class_name: 'Skill'
belongs_to :possessed_skill, class_name: 'Skill'
end
So, after thinking on this for a while, I have no idea what the proper way to model this is.
I have a website focused on sharing images. In order to make the users happy, I want them to be able to subscribe to many different collections of images.
So far, there's two types of collections. One is a "creator" relationship, which defines people who worked on a specific image. That looks like this:
class Image < ActiveRecord::Base
has_many :creations
has_and_belongs_to_many :locations
has_many :creators, through: :creations
end
class Creator < ActiveRecord::Base
has_many :images, ->{uniq}, through: :creations
has_many :creations
belongs_to :user
end
class Creation < ActiveRecord::Base
belongs_to :image
belongs_to :creator
end
Users may also tag an image with a subjective tag, which is something not objectively present in the image. Typical subjective tags would include "funny" or "sad," that kind of stuff. That's implemented like this:
class SubjectiveTag < ActiveRecord::Base
# Has a "name" field. The reason why the names of tags are a first-class DB model
# is so we can display how many times a given image has been tagged with a specific tag
end
class SubjectiveCollection < ActiveRecord::Base
# Basically, "User X tagged image Y with tag Z"
belongs_to :subjective_tag
belongs_to :user
has_many :images, through: :subjective_collection_member
end
class SubjectiveCollectionMember < ActiveRecord::Base
belongs_to :subjective_collection
belongs_to :image
end
I want users to be able to subscribe to both Creators and SubjectiveTags, and to display all images in those collections, sequentially, on the home page when they log in.
What is the best way to do this? Should I have a bunch of different subscription types - for example, one called SubjectiveTagSubscription and one called CreatorSubscription? If I do go this route, what is the most efficient way to retrieve all images in each collection?
What you want to use is a Polymorphic Association.
In your case, it would look like this:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :subscribeable, polymorphic: true
end
The subscriptions table would need to include the following fields:
user_id (integer)
subscribeable_id (integer)
subscribeable_type (string)
This setup will allow a subscription to refer to an instance of any other model, as ActiveRecord will use the subscribeable_type field to record the class name of the thing being subscribed to.
To produce a list of images for the currently logged in user, you could do this:
Subscription.where(user_id: current_user.id).map do |subscription|
subscription.subscribeable.images.all
end.flatten
If the performance implications of the above approach are intolerable (one query per subscription), you could collapse your two types of subscribeables into a single table via STI (which doesn't seem like a good idea here, as the two tables aren't very similar) or you could go back to your initial suggestion of having two different types of subscription models/tables, querying each one separately for subscriptions.
I have the following models:
class Instance < ActiveRecord::Base
has_many :users
has_many :books
end
class User < ActiveRecord::Base
belongs_to :instance
end
class Book < ActiveRecord::Base
belongs_to :instance
end
I now want to add a BookRevision table, that has the following columns
(id, user_id, version # (auto increment), diff (old book copy),
timestamps)
Logic:
When a book is Created, a record is
added to the BookRevision table, so
we know who created the book in the
first place
When a book is Updated, a record is added with the user_id (could be
a different user), and a new version
, and the old book text, to serve as an archive.
Given that I have the Instance, User, Book table implement in my rails
add, are these the correct steps to make the above come to life?
- Add a migration for the BookRevision table....
rails generate migration AddTableBookRevision user_id:integer
version:integer diff:text
- Then update the models as follows:
class Instance < ActiveRecord::Base
has_many :users
has_many :books
end
class User < ActiveRecord::Base
belongs_to :instance
end
class Book < ActiveRecord::Base
belongs_to :instance
has_many :BookRevisions
end
class BookRevision < ActiveRecord::Base
belongs_to :Book
end
Then in my controller, when adding a new book? Right now I have:
#book = Book.create(params[:book].merge(:instance_id =>
current_user.instance_id))
How do I update that to account for the BookRevision association?
Thanks for helping me out!
You might want to check out something like acts_as_versioned instead of rolling your own. This works in the fashion you've described here, where modifications are saved into a separate but related table.
Keep in mind you will have to apply migrations to your Book and BookRevision table in parallel from that point forward. They must be schema compatible for revisioning to work.
I have built a version tracking system of this sort that used serialized models to avoid having to maintain migrations, as the intent was to preserve the exact state of the model regardless of future modifications via migrations. This has the disadvantage of not being able to roll back to an arbitrary older version because there may be a schema mis-match.
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.