From e440d40fb1f5f83835388a37f634d249516966be Mon Sep 17 00:00:00 2001 From: Nour E-Din El-Nhass Date: Sun, 20 Jul 2025 15:31:58 +0300 Subject: [PATCH 1/2] Add support for active record read_attribute public method --- lib/rspec/active_model/mocks/mocks.rb | 3 ++ .../active_model/mocks/mock_model_spec.rb | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/lib/rspec/active_model/mocks/mocks.rb b/lib/rspec/active_model/mocks/mocks.rb index 8cfe696..5b1aa9a 100644 --- a/lib/rspec/active_model/mocks/mocks.rb +++ b/lib/rspec/active_model/mocks/mocks.rb @@ -61,6 +61,9 @@ def [](key) # alternative to record['id'] alias_method :_read_attribute, :[] + # Rails>7.1 added read_attribute for external usage similar to record['id'] + alias_method :read_attribute, :[] + # Returns the opposite of `persisted?` def new_record? !persisted? diff --git a/spec/rspec/active_model/mocks/mock_model_spec.rb b/spec/rspec/active_model/mocks/mock_model_spec.rb index d936aa0..364576e 100644 --- a/spec/rspec/active_model/mocks/mock_model_spec.rb +++ b/spec/rspec/active_model/mocks/mock_model_spec.rb @@ -482,6 +482,44 @@ def self.===(_other) end end + describe "attribute access methods" do + it "supports [] method with symbol" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model[:name]).to eq("John") + expect(model[:age]).to eq(25) + end + + it "supports [] method with string" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model["name"]).to eq("John") + expect(model["age"]).to eq(25) + end + + it "supports read_attribute method with symbol" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model.read_attribute(:name)).to eq("John") + expect(model.read_attribute(:age)).to eq(25) + end + + it "supports read_attribute method with string" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model.read_attribute("name")).to eq("John") + expect(model.read_attribute("age")).to eq(25) + end + + it "supports _read_attribute method with symbol" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model._read_attribute(:name)).to eq("John") + expect(model._read_attribute(:age)).to eq(25) + end + + it "supports _read_attribute method with string" do + model = mock_model(MockableModel, :name => "John", :age => 25) + expect(model._read_attribute("name")).to eq("John") + expect(model._read_attribute("age")).to eq(25) + end + end + describe "ActiveModel Lint tests" do # rubocop:disable Lint/EmptyExpression,Metrics/BlockNesting begin From aea568b698c211aa53ce1a3193e3619f9fac2551 Mon Sep 17 00:00:00 2001 From: NourElDin ELNhass Date: Sun, 3 Aug 2025 16:30:23 +0300 Subject: [PATCH 2/2] Fix rubocop issues --- lib/rspec/active_model/mocks/mocks.rb | 2 ++ spec/rspec/active_model/mocks/mock_model_spec.rb | 2 ++ spec/support/ar_classes.rb | 3 +++ 3 files changed, 7 insertions(+) diff --git a/lib/rspec/active_model/mocks/mocks.rb b/lib/rspec/active_model/mocks/mocks.rb index 5b1aa9a..07a1464 100644 --- a/lib/rspec/active_model/mocks/mocks.rb +++ b/lib/rspec/active_model/mocks/mocks.rb @@ -106,6 +106,7 @@ def mock_model(string_or_model_class, stubs={}) model_class = Object.const_set(string_or_model_class, Class.new do # rubocop:disable Style/SingleLineMethods extend ::ActiveModel::Naming + def self.primary_key; :id; end # For detection of being a valid association in 7+ @@ -149,6 +150,7 @@ def self.param_delimiter; "-"; end msingleton = class << m; self; end msingleton.class_eval do include ActiveModelInstanceMethods + include ActiveRecordInstanceMethods if defined?(ActiveRecord) include ActiveModel::Conversion include ActiveModel::Validations diff --git a/spec/rspec/active_model/mocks/mock_model_spec.rb b/spec/rspec/active_model/mocks/mock_model_spec.rb index 364576e..8d32d7f 100644 --- a/spec/rspec/active_model/mocks/mock_model_spec.rb +++ b/spec/rspec/active_model/mocks/mock_model_spec.rb @@ -557,6 +557,7 @@ def self.===(_other) ERR end include Test::Unit::Assertions + if defined?((Test::Unit::AutoRunner.need_auto_run = ())) Test::Unit::AutoRunner.need_auto_run = false elsif defined?((Test::Unit.run = ())) @@ -570,6 +571,7 @@ def self.===(_other) else require 'test/unit/assertions' include Test::Unit::Assertions + if defined?((Test::Unit::AutoRunner.need_auto_run = ())) Test::Unit::AutoRunner.need_auto_run = false elsif defined?((Test::Unit.run = ())) diff --git a/spec/support/ar_classes.rb b/spec/support/ar_classes.rb index 6d05540..19c27c7 100644 --- a/spec/support/ar_classes.rb +++ b/spec/support/ar_classes.rb @@ -41,6 +41,7 @@ class NonActiveRecordModel class MockableModel < ActiveRecord::Base extend Connections + has_one :associated_model end @@ -54,6 +55,7 @@ class SubMockableModel < MockableModel class AssociatedModel < ActiveRecord::Base extend Connections + belongs_to :mockable_model belongs_to :nonexistent_model, :class_name => "Other" end @@ -61,5 +63,6 @@ class AssociatedModel < ActiveRecord::Base class AlternatePrimaryKeyModel < ActiveRecord::Base self.primary_key = :my_id extend Connections + attr_accessor :my_id end