Permalink
Browse files

Make :through associations look for the through_reflection and source…

…_reflection.
  • Loading branch information...
1 parent a39ce3b commit d64dd60e7f3ae9409ffc92c581965a7f3534f337 @josevalim josevalim committed Apr 20, 2009
View
@@ -62,7 +62,7 @@ def self.configure_gemspec!
########### Common specs
-gem 'rspec', ENV['RSPEC_VERSION'] || '1.2.2'
+gem 'rspec'
require 'spec/rake/spectask'
desc "Run the specs under spec"
@@ -10,7 +10,7 @@ class AssociationMatcher < Remarkable::ActiveRecord::Base #:nodoc:
# Stores optionals declared above in a CONSTANT to generate assertions
ASSOCIATION_OPTIONS = self.matcher_optionals
- collection_assertions :association_exists?, :macro_matches?, :through_exists?,
+ collection_assertions :association_exists?, :macro_matches?, :through_exists?, :source_exists?,
:join_table_exists?, :foreign_key_exists?, :polymorphic_exists?,
:counter_cache_exists?
@@ -26,15 +26,21 @@ def macro_matches?
def through_exists?
return true unless @options.key?(:through)
- subject_class.reflect_on_association(@options[:through])
+ reflection.through_reflection rescue false
+ end
+
+ def source_exists?
+ return true unless @options.key?(:through)
+ reflection.source_reflection rescue false
end
def join_table_exists?
- return true unless has_join_table?
- ::ActiveRecord::Base.connection.tables.include?(reflection_join_table)
+ return true unless reflection.macro == :has_and_belongs_to_many
+ ::ActiveRecord::Base.connection.tables.include?(reflection.options[:join_table])
end
def foreign_key_exists?
+ return true unless foreign_key_table
table_has_column?(foreign_key_table, reflection_foreign_key)
end
@@ -76,27 +82,25 @@ def reflection_foreign_key
reflection.primary_key_name.to_s
end
- def reflection_join_table
- (reflection.options[:join_table] || reflection.options[:through]).to_s
- end
-
- def has_join_table?
- reflection.options.key?(:through) || reflection.macro == :has_and_belongs_to_many
- end
-
def table_has_column?(table_name, column)
::ActiveRecord::Base.connection.columns(table_name, 'Remarkable column retrieval').any?{|c| c.name == column }
end
+ # In through we don't check the foreign_key, because it's spread
+ # accross the through and the source reflection which should be tested
+ # with their own macros.
+ #
# In cases a join table exists (has_and_belongs_to_many and through
# associations), we check the foreign key in the join table.
#
# On belongs to, the foreign_key is in the subject class table and in
# other cases it's on the reflection class table.
#
def foreign_key_table
- if has_join_table?
- reflection_join_table
+ if reflection.options.key?(:through)
+ nil
+ elsif reflection.macro == :has_and_belongs_to_many
+ reflection.options[:join_table]
elsif reflection.macro == :belongs_to
subject_class.table_name
else
@@ -33,6 +33,7 @@ en:
association_exists: "{{subject_name}} records {{macro}} {{association}}, got no association"
macro_matches: "{{subject_name}} records {{macro}} {{association}}, got {{subject_name}} records {{actual_macro}} {{association}}"
through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
+ source_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, source association does not exist"
join_table_exists: "join table {{actual_join_table}} to exist, but does not"
foreign_key_exists: "foreign key {{actual_foreign_key}} to exist on {{foreign_key_table}}, but does not"
polymorphic_exists: "{{subject_table}} to have {{polymorphic_column}} as column, but does not"
@@ -354,11 +354,11 @@ def define_and_validate(options={})
define_model :project_task, columns do
belongs_to :task
belongs_to :project
- end unless options.delete(:skip_through)
+ end unless options.delete(:skip_source)
@model = define_model :project, options.delete(:model_columns) || {} do
+ has_many :project_tasks unless options.delete(:skip_through)
has_many :tasks, options
- has_many :project_tasks
end
have_many :tasks
@@ -403,15 +403,15 @@ def define_and_validate(options={})
end
it 'should set through_exists? message' do
- matcher = define_and_validate(:through => 'project_tasks')
- matcher.through(:another).matches?(@model)
- matcher.failure_message.should == 'Expected Project records have many tasks through :another, through association does not exist'
+ matcher = define_and_validate(:through => :project_tasks, :skip_through => true)
+ matcher.through(:project_tasks).matches?(@model)
+ matcher.failure_message.should == 'Expected Project records have many tasks through :project_tasks, through association does not exist'
end
- it 'should set join_table_exists? message' do
- matcher = define_and_validate(:through => 'project_tasks', :skip_through => true)
+ it 'should set source_exists? message' do
+ matcher = define_and_validate(:through => :project_tasks, :skip_source => true)
matcher.through(:project_tasks).matches?(@model)
- matcher.failure_message.should == 'Expected join table "project_tasks" to exist, but does not'
+ matcher.failure_message.should == 'Expected Project records have many tasks through :project_tasks, source association does not exist'
end
end
@@ -456,11 +456,11 @@ def define_and_validate(options={})
end
describe 'with through option' do
- it { should define_and_validate(:through => 'project_tasks') }
- it { should define_and_validate(:through => 'project_tasks').through(:project_tasks) }
+ it { should define_and_validate(:through => :project_tasks) }
+ it { should define_and_validate(:through => :project_tasks).through(:project_tasks) }
- it { should_not define_and_validate(:through => 'project_tasks').through(:something) }
- it { should_not define_and_validate(:through => 'project_tasks', :skip_through => true).through(:project_tasks) }
+ it { should_not define_and_validate(:through => :project_tasks).through(:something) }
+ it { should_not define_and_validate(:through => :project_tasks, :skip_through => true).through(:project_tasks) }
end
create_optional_boolean_specs(:uniq, self)
@@ -470,7 +470,7 @@ def define_and_validate(options={})
end
describe 'macros' do
- before(:each){ define_and_validate(:through => 'project_tasks', :readonly => true, :validate => true) }
+ before(:each){ define_and_validate(:through => :project_tasks, :readonly => true, :validate => true) }
should_have_many :tasks
should_have_many :tasks, :readonly => true
@@ -493,11 +493,11 @@ def define_and_validate(options={})
define_model :project_manager, columns do
belongs_to :manager
belongs_to :project
- end unless options.delete(:skip_through)
+ end unless options.delete(:skip_source)
@model = define_model :project, options.delete(:model_columns) || {} do
+ has_many :project_managers unless options.delete(:skip_through)
has_one :manager, options
- has_many :project_managers
end
have_one :manager
@@ -536,15 +536,15 @@ def define_and_validate(options={})
end
it 'should set through_exists? message' do
- matcher = define_and_validate(:through => 'project_managers')
- matcher.through(:another).matches?(@model)
- matcher.failure_message.should == 'Expected Project records have one manager through :another, through association does not exist'
+ matcher = define_and_validate(:through => :project_managers, :skip_through => true)
+ matcher.through(:project_managers).matches?(@model)
+ matcher.failure_message.should == 'Expected Project records have one manager through :project_managers, through association does not exist'
end
- it 'should set join_table_exists? message' do
- matcher = define_and_validate(:through => 'project_managers', :skip_through => true)
+ it 'should set source_exists? message' do
+ matcher = define_and_validate(:through => :project_managers, :skip_source => true)
matcher.through(:project_managers).matches?(@model)
- matcher.failure_message.should == 'Expected join table "project_managers" to exist, but does not'
+ matcher.failure_message.should == 'Expected Project records have one manager through :project_managers, source association does not exist'
end
end
@@ -589,19 +589,19 @@ def define_and_validate(options={})
end
describe 'with through option' do
- it { should define_and_validate(:through => 'project_managers') }
- it { should define_and_validate(:through => 'project_managers').through(:project_managers) }
+ it { should define_and_validate(:through => :project_managers) }
+ it { should define_and_validate(:through => :project_managers).through(:project_managers) }
- it { should_not define_and_validate(:through => 'project_managers').through(:something) }
- it { should_not define_and_validate(:through => 'project_managers', :skip_through => true).through(:project_managers) }
+ it { should_not define_and_validate(:through => :project_managers).through(:something) }
+ it { should_not define_and_validate(:through => :project_managers, :skip_through => true).through(:project_managers) }
end
create_optional_boolean_specs(:validate, self)
create_optional_boolean_specs(:autosave, self) if RAILS_VERSION =~ /^2.3/
end
describe 'macros' do
- before(:each){ define_and_validate(:through => 'project_managers', :validate => true) }
+ before(:each){ define_and_validate(:through => :project_managers, :validate => true) }
should_have_one :manager
should_have_one :manager, :validate => true
View
@@ -140,6 +140,7 @@ en:
association_exists: "{{subject_name}} records {{macro}} {{association}}, got no association"
macro_matches: "{{subject_name}} records {{macro}} {{association}}, got {{subject_name}} records {{actual_macro}} {{association}}"
through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
+ source_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, source association does not exist"
join_table_exists: "join table {{actual_join_table}} to exist, but does not"
foreign_key_exists: "foreign key {{actual_foreign_key}} to exist on {{foreign_key_table}}, but does not"
polymorphic_exists: "{{subject_table}} to have {{polymorphic_column}} as column, but does not"
@@ -139,7 +139,8 @@ pt-BR:
expectations:
association_exists: "{{subject_name}} pudesse {{macro}} {{association}}, obtive nenhuma associação"
macro_matches: "{{subject_name}} pudesse {{macro}} {{association}}, obtive que {{subject_name}} deve {{actual_macro}} {{association}}"
- through_exists: "{{subject_name}} pudesse {{macro}} {{association}} através de {{through}}, obtive que {{through}} não existe"
+ through_exists: "{{subject_name}} pudesse {{macro}} {{association}} através de {{through}}, obtive que \"through_association\" não existe"
+ source_exists: "{{subject_name}} pudesse {{macro}} {{association}} através de {{through}}, obtive que \"source association\" não existe"
join_table_exists: "tabela de junção {{actual_join_table}} existisse, mas não existe"
foreign_key_exists: "chave estrangeira {{actual_foreign_key}} existisse em {{foreign_key_table}}, mas não existe"
polymorphic_exists: "{{subject_table}} tivesse {{polymorphic_column}} como coluna, mas não tem"

0 comments on commit d64dd60

Please sign in to comment.