1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/test/models/developer.rb
Ryuta Kamizono cbb19eb833 Fix complicated has_many through with nested where condition
#40779 will be caused if (1) having nested where condition for through
association, and (2) through scope has references values, and (3) the
model has no association which is the same name with table name.

In that case, the join root will be found by the table name but the join
root isn't related with association reflection.

This changes to return the table klass from join dependency tree, it
works regardless of whether the join root or join association children.

Fixes #40779.
2021-01-05 11:40:04 +09:00

350 lines
9.9 KiB
Ruby

# frozen_string_literal: true
require "ostruct"
class Developer < ActiveRecord::Base
module TimestampAliases
extend ActiveSupport::Concern
included do
alias_attribute :created_at, :legacy_created_at
alias_attribute :updated_at, :legacy_updated_at
alias_attribute :created_on, :legacy_created_on
alias_attribute :updated_on, :legacy_updated_on
end
end
include TimestampAliases
module ProjectsAssociationExtension2
def find_least_recent
order("id ASC").first
end
end
self.ignored_columns = %w(first_name last_name)
has_and_belongs_to_many :projects do
def find_most_recent
order("id DESC").first
end
end
belongs_to :mentor
belongs_to :strict_loading_mentor, strict_loading: true, foreign_key: :mentor_id, class_name: "Mentor"
accepts_nested_attributes_for :projects
has_and_belongs_to_many :shared_computers, class_name: "Computer"
has_and_belongs_to_many :projects_extended_by_name,
-> { extending(ProjectsAssociationExtension) },
class_name: "Project",
join_table: "developers_projects",
association_foreign_key: "project_id"
has_and_belongs_to_many :projects_extended_by_name_twice,
-> { extending(ProjectsAssociationExtension, ProjectsAssociationExtension2) },
class_name: "Project",
join_table: "developers_projects",
association_foreign_key: "project_id"
has_and_belongs_to_many :projects_extended_by_name_and_block,
-> { extending(ProjectsAssociationExtension) },
class_name: "Project",
join_table: "developers_projects",
association_foreign_key: "project_id" do
def find_least_recent
order("id ASC").first
end
end
has_and_belongs_to_many :strict_loading_projects,
join_table: :developers_projects,
association_foreign_key: :project_id,
class_name: "Project",
strict_loading: true
has_and_belongs_to_many :special_projects, join_table: "developers_projects", association_foreign_key: "project_id"
has_and_belongs_to_many :sym_special_projects,
join_table: :developers_projects,
association_foreign_key: "project_id",
class_name: "SpecialProject"
has_many :audit_logs
has_many :required_audit_logs, class_name: "AuditLogRequired"
has_many :strict_loading_audit_logs, -> { strict_loading }, class_name: "AuditLog"
has_many :strict_loading_opt_audit_logs, strict_loading: true, class_name: "AuditLog"
has_many :contracts
has_many :firms, through: :contracts, source: :firm
has_many :comments, ->(developer) { where(body: "I'm #{developer.name}") }
has_many :ratings, through: :comments
has_one :ship, dependent: :nullify
has_one :strict_loading_ship, strict_loading: true, class_name: "Ship"
belongs_to :firm
has_many :contracted_projects, class_name: "Project"
scope :jamises, -> { where(name: "Jamis") }
validates_inclusion_of :salary, in: 50000..200000
validates_length_of :name, within: 3..20
before_create do |developer|
developer.audit_logs.build message: "Computer created"
end
attribute :last_name
def log=(message)
audit_logs.build message: message
end
after_find :track_instance_count
cattr_accessor :instance_count
def track_instance_count
self.class.instance_count ||= 0
self.class.instance_count += 1
end
private :track_instance_count
end
class SubDeveloper < Developer
end
class SpecialDeveloper < ActiveRecord::Base
self.table_name = "developers"
has_many :special_contracts, foreign_key: "developer_id"
end
class SymbolIgnoredDeveloper < ActiveRecord::Base
self.table_name = "developers"
self.ignored_columns = [:first_name, :last_name]
attribute :last_name
end
class AuditLog < ActiveRecord::Base
belongs_to :developer, validate: true
belongs_to :unvalidated_developer, class_name: "Developer"
end
class AuditLogRequired < ActiveRecord::Base
self.table_name = "audit_logs"
belongs_to :developer, required: true
end
class DeveloperWithBeforeDestroyRaise < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, join_table: "developers_projects", foreign_key: "developer_id"
before_destroy :raise_if_projects_empty!
def raise_if_projects_empty!
raise if projects.empty?
end
end
class DeveloperWithSelect < ActiveRecord::Base
self.table_name = "developers"
default_scope { select("name") }
end
class DeveloperwithDefaultMentorScopeNot < ActiveRecord::Base
self.table_name = "developers"
default_scope -> { where(mentor_id: 1) }
end
class DeveloperWithDefaultMentorScopeAllQueries < ActiveRecord::Base
self.table_name = "developers"
default_scope -> { where(mentor_id: 1) }, all_queries: true
end
class DeveloperWithIncludes < ActiveRecord::Base
self.table_name = "developers"
has_many :audit_logs, foreign_key: :developer_id
default_scope { includes(:audit_logs) }
end
class DeveloperFilteredOnJoins < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
def self.default_scope
joins(:projects).where(projects: { name: "Active Controller" })
end
end
class DeveloperOrderedBySalary < ActiveRecord::Base
include Developer::TimestampAliases
self.table_name = "developers"
default_scope { order("salary DESC") }
scope :by_name, -> { order("name DESC") }
end
class DeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
default_scope { where("name = 'David'") }
end
class LazyLambdaDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
default_scope lambda { where(name: "David") }
end
class LazyBlockDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
default_scope { where(name: "David") }
end
class CallableDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
default_scope OpenStruct.new(call: where(name: "David"))
end
class ClassMethodDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
def self.default_scope
where(name: "David")
end
end
class ClassMethodReferencingScopeDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
scope :david, -> { where(name: "David") }
def self.default_scope
david
end
end
class LazyBlockReferencingScopeDeveloperCalledDavid < ActiveRecord::Base
self.table_name = "developers"
scope :david, -> { where(name: "David") }
default_scope { david }
end
class DeveloperCalledJamis < ActiveRecord::Base
include Developer::TimestampAliases
self.table_name = "developers"
default_scope { where(name: "Jamis") }
scope :poor, -> { where("salary < 150000") }
scope :david, -> { where name: "David" }
scope :david2, -> { unscoped.where name: "David" }
end
class PoorDeveloperCalledJamis < ActiveRecord::Base
self.table_name = "developers"
default_scope -> { where(name: "Jamis", salary: 50000) }
end
class InheritedPoorDeveloperCalledJamis < DeveloperCalledJamis
self.table_name = "developers"
default_scope -> { where(salary: 50000) }
end
class MultiplePoorDeveloperCalledJamis < ActiveRecord::Base
self.table_name = "developers"
default_scope { }
default_scope -> { where(name: "Jamis") }
default_scope -> { where(salary: 50000) }
end
module SalaryDefaultScope
extend ActiveSupport::Concern
included { default_scope { where(salary: 50000) } }
end
class ModuleIncludedPoorDeveloperCalledJamis < DeveloperCalledJamis
self.table_name = "developers"
include SalaryDefaultScope
end
class EagerDeveloperWithDefaultScope < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
default_scope { includes(:projects) }
end
class EagerDeveloperWithClassMethodDefaultScope < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
def self.default_scope
includes(:projects)
end
end
class EagerDeveloperWithLambdaDefaultScope < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
default_scope lambda { includes(:projects) }
end
class EagerDeveloperWithBlockDefaultScope < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
default_scope { includes(:projects) }
end
class EagerDeveloperWithCallableDefaultScope < ActiveRecord::Base
self.table_name = "developers"
has_and_belongs_to_many :projects, -> { order("projects.id") }, foreign_key: "developer_id", join_table: "developers_projects"
default_scope OpenStruct.new(call: includes(:projects))
end
class ThreadsafeDeveloper < ActiveRecord::Base
self.table_name = "developers"
def self.default_scope
Thread.current[:default_scope_delay].call
limit(1)
end
end
class CachedDeveloper < ActiveRecord::Base
include Developer::TimestampAliases
self.table_name = "developers"
self.cache_timestamp_format = :number
end
class DeveloperWithIncorrectlyOrderedHasManyThrough < ActiveRecord::Base
self.table_name = "developers"
has_many :companies, through: :contracts
has_many :contracts, foreign_key: :developer_id
end
class DeveloperName < ActiveRecord::Type::String
def deserialize(value)
"Developer: #{value}"
end
end
class AttributedDeveloper < ActiveRecord::Base
self.table_name = "developers"
attribute :name, DeveloperName.new
self.ignored_columns += ["name"]
end
class ColumnNamesCachedDeveloper < ActiveRecord::Base
self.table_name = "developers"
self.ignored_columns += ["name"] if column_names.include?("name")
end