Ruby finding all objects where has_one relation is true and is in array - ruby

I am currently trying to implement a has_one relationship where you are able to search through all of blogs active posts. My problem comes where even though i explicitly search through the active_post relation it will return everything in its posts instead and not just the active ones which is what i want.
# == Schema Information
#
# Table name: blog
#
# id :integer not null, primary key
# name :string(200)
# context :string(20)
# show_on_summary :boolean
#
class Blog < ApplicationRecord
has_many :posts, dependent: :destroy, autosave: true
has_one :active_post, -> { order('created_at DESC').where(posts: { status_code: 'active' }) }, class_name: 'Post', foreign_key: :blog_id
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
# status_code :string(20)
# blog_id :integer
#
class Post < ApplicationRecord
STATUS_CODES = %w(active pending deactivated)
belongs_to :blog
and yet when i run the code below where i have a list of posts of any type of status_code and am trying to find the blog where only their active_post relation matches, it will return every blog that has a post in that list regardless of status_code.
Blog.where(active_post: list_of_posts)
When i am debugging i can go to the individual blogs and look at their 'active_post' relation and it will show the correct latest active post. if there is no active post it will return nil which is what i want.

I don't think you can do it without manually joining your table
Blog.joins(:active_post).where(posts: { id: list_of_posts })
When you join your table, you ensure that the relation is going to be used, and specifying the "posts"."id" column also ensures that it won't use a subquery to match the Blogs ids

I think you don't need to specify the :posts table in the where clause:
class Blog < ApplicationRecord
has_many :posts, dependent: :destroy, autosave: true
has_one :active_post, -> { order('created_at DESC').where(status_code: 'active') }, class_name: 'Post', foreign_key: :blog_id
#...
end
Blog.first.active_post
# => return the latest post

Related

searching through joined polymorphic association with table_name defined

i have two models
class Profession < ApplicationRecord
has_many :users
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :scope, polymorphic: true
end
and a query:
Profession.joins(:users).where(accounts: {scope: some_scope_variable })
when I run that i get
Mysql2::Error: Unknown column 'accounts.scope' in 'where clause'
what i also tried is
Profession.joins(:users).where(users: {scope: some_scope_variable })
but it also doesnt work and gives similar error
Mysql2::Error: Unknown column 'users.scope' in 'where clause'
According to the documentation, polymorphic associations rely on two columns being present on the model. Example
class User < ApplicationRecord
belongs_to :thingable, polymorphic: true
end
These columns should exist on users:
thingable_id
thingable_type
If you want to query them through an association, you may use the columns directly, like:
Profession.joins(:user).where(users: { thingable_id: 42, thingable_type: 'Foo' })
Also, I'd reconsider the name scope, since this is used by Rails already.
EDIT:
After submitting the answer above, I started understanding your question, sorry about this.
I reproduced it and made it work like this:
class Profession < ApplicationRecord
has_many :users, as: :thingable # <-- this is missing in your case
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :profession
belongs_to :thingable, polymorphic: true
end
Now we can do this:
Profession.joins(:users).where(accounts: { age: (20..30) })
The WHERE-clause on the joined table is translated to SQL without any magic and checks:
WHERE `accounts`.`age` BETWEEN 20 AND 30
Whereas, the WHERE-clause on self-columns are sometimes magically modified:
User.where(thingable: 42)
results in
WHERE `accounts`.`thingable_id` = 42
-- ^^^ added by Rails
So, if we want to filter on any of these polymorphic columns, we do
Profession.joins(:users).where(accounts: { thingable_id: 111 })

How to join 1:N tables in rails and instead of multiple rows for record get one row with extra column containing array of IDs from joined table

I have 3 models
class Mission < ActiveRecord::Base
belongs_to :guild
end
class Guild < ActiveRecord::Base
has_many :missions
has_many :guild_coordinators, :dependent => :destroy
has_many :coordinators, :through=> :guild_coordinators, :class_name => "Associate"
end
class GuildCoordinator < ActiveRecord::Base
belongs_to :guild
belongs_to :coordinator, :class_name => "Associate"
end
If I do
Mission.joins(:guild => :guild_coordinators)
I get row for every guild -> guild coordinator association
Is it possible to get unique records for Missions with joined Guilds and in one column get IDs of all coordinators in an Array?
edit:
expected result is something like this:
#<ActiveRecord::Relation [#<Mission id: 13, fy: 2018, guild_id: 31, name: "test mission", status: 0, coordinators: [1,2,3,5,8]>
my database is postgres
as output I need Active Record relation for gem ajax-datatables-rails
With Postgresql you can use array_agg aggregate function:
Mission.
joins(guild: :guild_coordinators).
select('missions.*, array_agg(guild_coordinators.id) as coordinators').
group(:id)
And you get exactly ActiveRecord::Relation, which will contain(after call) Mission objects with additional field coordinators:Array.
The second option is to use .includes like my or #garrett-motzner comments show.

1 user model with student,tutor role + different profile for student, tutor?

How to correctly setup a User model with 2 roles, and have 2 separate profile models for each of the roles? Im confused on how to implement. Currently im using this but it fails:
models/user.rb
# id :integer ( only important columns noted to save space)
# profile_id :integer
# profile_type :string(255)
belongs_to :profile, :polymorphic => true
models/profile_student.rb:
# user_id :integer
has_one :user, as: :profile, dependent: :destroy
models/profile_tutor.rb:
# user_id :integer
has_one :user, as: :profile, dependent: :destroy
How to correctly get the profile for a user??
for example using devise.
#user = current_user.profile
I would try having two types of users: student and tutor. In order to do this, in your user table, have a column called type and put in a validation that ensures it is either student or tutor:
validates :type, :inclusion => {:in => ['student', 'tutor']}
Then create a Student model and a Tutor model. In rails, 'type' is a special kind of attribute in which rails will know that it is referring to other models. Then, in order to make profiles, you have two options. You can either say that both a student and a tutor has_one :profile, or you can separate the types of profiles.
For example, you can do:
class Student < User
has_one :profile
end
class Tutor < User
has_one :profile
end
If both profiles have similar types of information, that may work for you. However, if a tutor and student have considerably different profiles, try something like this:
class Student < User
has_one :student_profile
end
class Tutor < User
has_one :tutor_profile
end
and then create a separate model for each type of profile.
By using this 'type' column, you can make it so that students and tutors inherit all the methods and properties of users, but can also have their own distinct properties and methods.

Polymorphic show many items

I am trying to create a polymorphic relationships and to show them.
Here my relationships
events
has_many :comments, :as => :commentable
users
has_many :comments, :as => :commentable
comments
belongs_to :comments, :polymorphic => true
comments has the following models
# commentable_id :integer
# commentable_type :string(255)
Now my goals would be show on event#index items related to the events but also to shows all comments.description according to each events sorta has follow
********************* *********************
Event.title Event.title
Event.description Event.description
{Comment.body} {Comment.body}
... ...
********************** **********************
and so on.
Here my controller
def index
#mosttop = Event.all[1..-1]
#loc = #mosttop.comments
end
If i do this however i get an undefined locations. I am wondering what i am doing wrong. Also, my routes is has follow
resources :events do
resources :comments do
end
Also at the moment I haven't create a relationship using build, but just when at the link event/1/comments and create it
the controller is has follow
def create
#comment = #commentable.comments.new(params[:comment])
...
end
private
def load_commentable
resource, id = request.path.split('/')[1,2]
#commentable = resource.singularize.classify.constantize.find(id)
end
end

Traversal of Complex Data Structure in a Rails Application

I have a data structure in which Topics have subtopics, which again have subtopics, continuing down from the original Topic about six levels. Each of these topics has multiple subtopics.
I'm looking for a way to traverse this data and bring back data affiliated from each of the subtopics... as if pulling the data I want "downstream".
For example Given a topic structure:
Harry_Potter > Characters > Slitherin_House.videos
(Assuming that slitherin house has subtopics for each of the members, Malfoy, Crabbe, etc. ) I want the videos for each of the members to appear in the video lists for Slitherin_House, Characters, and Harry_Potter (each of the ancestors).
I've been looking around and stumbled across Ancestry and Acts As Tree and read through the code and tried my hand at using them, but they seem more oriented around the ancestor side of things, as opposed to accessing and pulling data from the children.
I also have tried my hand at using the associations
has_many :through, and has_and_belongs_to_many
but have been unsuccessful in my attempts to create a working traversal system. And can't seem to complete wrap my head around how to do this.
Does anyone have any ideas or suggestions on what to do given such a predicament? Or know of gems which provide for any such functionality?
Relationship class & model: (as it should flow like a stream)
class CreateStreams < ActiveRecord::Migration
def change
create_table :streams do |t|
t.integer :downstream_id
t.integer :upstream_id
t.timestamps
end
add_index :streams, :downstream_id
add_index :streams, :upstream_id
add_index :streams, [:downstream_id, :upstream_id], unique: true
end
end
# == Schema Information
#
# Table name: streams
#
# id :integer not null, primary key
# downstream_id :integer
# upstream_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Stream < ActiveRecord::Base
attr_accessible :downstream_id
belongs_to :subsidiary, class_name: "Topic"
belongs_to :tributary, class_name: "Topic"
validates :downstream_id, presence: true
validates :upstream_id, presence: true
end
Topic Model
# == Schema Information
#
# Table name: topics
#
# id :integer not null, primary key
# name :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# slug :string(255)
# wiki :string(255)
# summary :string(255)
class Topic < ActiveRecord::Base
extend FriendlyId
attr_accessible :name, :wiki, :summary
has_many :streams, foreign_key: "downstream_id", dependent: :destroy
has_many :tributaries, through: :streams, source: :tributary
has_many :reverse_streams, foreign_key: "upstream_id",
class_name: "Stream",
dependent: :destroy
has_many :subsidiaries, :through => :reverse_streams, source: :subsidiary
friendly_id :name, use: :slugged
validates :name, presence: true, length: { maximum: 50 },
uniqueness: { case_sensitive: false }
def downstream?(other_topic)
streams.find_by_downstream_id(other_topic.id)
end
def flow!(other_topic)
streams.create!(downstream_id: other_topic.id)
end
def dam!(other_topic)
streams.find_by_downstream_id(other_topic.id).destroy
end
end
Note: I also want to be able to assign a subtopic, multiple parents. So that characters could potentially get put underneath of "Actors" as well for example.
if you want to set this up in a simple way i'd go for a recursive relation. This means a topic can belong to another topic (nested)
The database model of the topic would look like:
Topic
id
topic_id
title
the model would then be:
class Topic < ActiveRecord::Base
belongs_to :topic
has_many :topics
end
Now if you have a topic. you can access its parents by doing .topic and its childs with .topics. A Topic with no parent is a toplevel one and a Topic with no childs is a end node.

Resources