I have a problem with using similar scopes in ActiveRecord. I have 3 models:
Person:
class Person < ActiveRecord::Base
has_many :survey_packs
def self.by_first_name(text)
where(first_name: text)
end
end
SurveyPack:
class SurveyPack < ActiveRecord::Base
has_many :survey_instances, inverse_of: :survey_pack
belongs_to :person
end
and SurveyInstance:
class SurveyInstance < ActiveRecord::Base
belongs_to :survey_pack, inverse_of: :survey_instances
belongs_to :student, class_name: 'Person', foreign_key: :person_id
scope :teacher_full_name, ->(text) { SurveyInstance.joins(:person).merge(Person.by_first_name(text)) }
scope :student_full_name, ->(text) { SurveyInstance.joins(:student).merge(Person.by_first_name(text)) }
end
The problem is that I cant join this scopes together:
scope :teacher_full_name, ->(text) { SurveyInstance.joins(:person).merge(Person.by_first_name(text)) }
scope :student_full_name, ->(text) { SurveyInstance.joins(:student).merge(Person.by_first_name(text)) }
For example I have a survey_instance that student name is: 'Student' and Teacher name is: 'Teacher':
SurveyInstance.teacher_full_name('Teacher') #this will work
SurveyInstance.student_full_name('Student') #this will also work
SurveyInstance.teacher_full_name('Teacher').student_full_name('Student') #this will not work...
I have no idea how to solve this problem...
Not sure whether this works or not, but the logic is similar to this:
class SurveyInstance < ActiveRecord::Base
belongs_to :survey_pack, inverse_of: :survey_instances
belongs_to :student, class_name: 'Person', foreign_key: :person_id
scope :full_name, ->(type, text) { SurveyInstance.joins(type).merge(Person.by_first_name(text)) }
end
Extract the association out so that the symbol is passed through the scope call.
To call the scope:
SurveyInstance.full_name(:person, 'Teacher')
SurveyInstance.full_name(:student, 'Student')
Related
I have the following models:
class User < ApplicationRecord
has_and_belongs_to_many :lists
end
class Workspace < ApplicationRecord
has_many :lists, dependent: :nullify
end
class List < ApplicationRecord
has_and_belongs_to_many :users
belongs_to :workspace, optional: true
scope :by_workspace, ->(workspace) { where(workspace: workspace) }
scope :by_user, ->(user) { joins(:users).where(users: { id: user }) }
end
What I need is a by_workspace_or_user scope, which returns any list which belongs to a given workspace or to a given user. I've tried combining these using or, but no luck.
You can use plain SQL where to achieve this:
List
.left_outer_joins(:users)
.where("users.id = ? OR lists.workspace_id = ?", user.id, workspace.id)
I have such db structure:
term.rb:
class Term < ActiveRecord::Base
has_many :tasks, through: :students
...
def accepted_tasks_count
tasks.where(status: Task.statuses[:accepted]).count
end
task.rb:
class Task < ActiveRecord::Base
has_many :notes, through: :submissions
...
def notes_count
self.notes.count
end
I need to add some method which will return accepted tasks without notes.
How can I do that?
Try this one:
class Task < ActiveRecord::Base
has_many :notes, through: :submissions
scope :accepted, -> { where(status: self.statuses[:accepted]) }
scope :without_notes, -> { includes(:notes).where(notes: { id: nil }) }
end
I've moved 'accepted tasks' query to the scope too, to make it reusable.
class Term < ActiveRecord::Base
has_many :tasks, through: :students
def accepted_tasks_count
tasks.accepted.count
end
end
To get all accepted tasks without notes, use this:
Task.accepted.without_notes
To get all accepted tasks without notes for the specific term, use that:
#term.tasks.accepted.without_notes
In my application, this is the schema:
class Route < ActiveRecord::Base
belongs_to :origin, class_name: 'Station'
belongs_to :destination, class_name: 'Station'
belongs_to :vehicle
has_many :trips
end
class Trip < ActiveRecord::Base
belongs_to :route
end
class Station < ActiveRecord::Base
has_many :origins, foreign_key: :origin_id, class_name: "Route"
has_many :destinations, foreign_key: :destination_id, class_name: "Route"
end
I'm trying to construct a scope within Trip that fetches all the trips that have either flown to OR from a particular Station. Right now, I'm accomplishing this .new_york scope as follows:
scope :to_new_york, -> { joins(route: :destination).where(["stations.name = ?", "New York City"]) }
scope :from_new_york, -> { joins(route: :origin).where(["stations.name = ?", "New York City"]) }
scope :new_york, -> { to_new_york + from_new_york }
Since I never intend to use to_new_york and from_new_york on their own (I only care about a collection that contains both groups), is there a way to write a single .new_york scope that does both jobs without having to write the component .to_ and .from_ scopes?
Is it possible to make a has_one relationship work like this?
I would like to be able able to load records like this:
#person = Person.find(1) => {Person id: 1, favorite_house_id: 10}
#person.favorite_house => {House id: 10....)
class Person < ActiveRecord::Base
has_many :houses, through: :person_houses
has_one :favorite_house, through: :person_houses
end
class PersonHouse < ActiveRecord::Base
belongs_to :house
belongs_to :person
end
class House < ActiveRecord::Base
has_many :people, through: :person_houses
end
Replace the has_one relation of Person by:
belongs_to :favorite_house, :class_name => "House"
Do not forget to create a column favorite_house_id in the table of Person.
i have following code:
class Item < ActiveRecord::Base
belongs_to :user
has_many :transactions
#scope :active, lambda??
end
class Transaction < ActiveRecord::Base
belongs_to :user
belongs_to :item
scope :active, where("status = 0")
end
class User < ActiveRecord::Base
has_many :items
has_many :transactions
end
i wish to build a scope in model Item to retrieve only records with active transactions, for example:
User.find(1).items.active
I found the answer. it shoud be this way:
scope :active, joins(:transactions)
Transaction.active
The answer was here: http://asciicasts.com/episodes/215-advanced-queries-in-rails-3