Rails 5.2 belongs_to association not linking to parent - ruby-on-rails

I have these models
class Version
has_many :bids
end
class Bid
belongs_to :version
end
in the console:
> bid = Bid.first
which returns
> #<Bid id: 8 version_id: 5, deleted_at: nil, created_at: "2018-09-06 00:32:32", updated_at: "2018-09-06 00:32:32", created_by_id: 3, updated_by_id: 3, selected: true>
but if i try to call the version it returns nil. the version is there though
> bid.version
> nil
> Version.find(bid.version_id)
> #<Version id: 5, effective_date: "2018-09-05 23:36:24", end_date: nil, created_at: "2018-09-05 23:36:24", updated_at: "2018-09-05 23:36:24", created_by_id: nil>
what is going on? what could I be doing wrong?

So it turns out that object.version is an existing rails method. if i change the relationship to belongs_to :pricing_version the code works.
Anyone with this issue in the future just avoid naming their class Version

Related

FactoryGirl creating extra records with has_many association

I'm running into an issue where FactoryGirl appears to be creating extra records with a has_many relationship.
Given these models:
class NextAction < ActiveRecord::Base
has_many :next_actions_orders
has_many :orders, through: :next_actions_orders
end
class NextActionsOrder < ActiveRecord::Base
belongs_to :order
belongs_to :next_action
end
class Order < ActiveRecord::Base
has_many :next_actions_orders
has_many :next_actions, through: :next_actions_orders
end
And these factories:
FactoryGirl.define do
factory :next_action do
status :pending
trait :pickup do
next_actions_orders { FactoryGirl.create_list(:next_actions_order, 1) }
action_type :pickup
end
trait :multiple_pickups do
next_actions_orders { FactoryGirl.create_pair(:next_actions_order) }
action_type :pickup
end
end
end
FactoryGirl.define do
factory :next_actions_order do
order { FactoryGirl.create(:order) }
next_action
end
end
FactoryGirl.define do
factory :order do
status :pending
end
end
As you can see in the NextAction factory, I ran into an issue setting up the NextActionOrder association.
I would usually have used next_actions_orders { FactoryGirl.create(:next_actions_order) } but with the has_many :next_actions_orders, I was getting an undefined method 'each' for #<NextActionsOrder... error.
next_actions_orders { FactoryGirl.create_list(:next_actions_order, 1) } seems to work as a workaround. As shown below, this doesn't seem to be the cause of the issue, since it also exists from the create_pair example.
The real issue is this:
it 'create_list generates duplicate FactoryGirl records' do
puts NextAction.count # output: 0
pickup = create(:next_action, :pickup)
puts NextAction.count # output: 2
## binding.pry
end
Succinctly, the create(:next_action) calls seem to be generating 1 additional NextAction record than is required.
I used pry to inspect this and sure enough, you can see this.
With pry inserted at the first location shown above, queries produce the following:
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextAction.all
=> [#<NextAction id: 2, ... created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>,
#<NextAction id: 3, ... created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextActionsOrder.all
=> [#<NextActionsOrder id: 1, next_action_id: 3, order_id: 2>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> Order.all
=> [#<Order id: 2, created_at: "2014-04-20 16:40:57", updated_at: "2014-04-20 16:40:57", status: 0>]
Here, everything looks great, except for NextAction ID #2. It's not associated anywhere, it's just an orphan record that was created for some reason.
Here's what happens with create_pair:
it 'create_pair generates duplicate FactoryGirl records' do
puts NextAction.count # output: 0
pickups = create(:next_action, :multiple_pickups)
puts NextAction.count # output: 3
## binding.pry
end
With pry inserted as shown, the same queries produce:
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextAction.all
=> [#<NextAction id: 4, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
#<NextAction id: 5, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
#<NextAction id: 6, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> NextActionsOrder.all
=> [#<NextActionsOrder id: 2, next_action_id: 6, order_id: 3>,
#<NextActionsOrder id: 3, next_action_id: 6, order_id: 4>]
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> Order.all
=> [#<Order id: 3, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>,
#<Order id: 4, created_at: "2014-04-20 16:53:20", updated_at: "2014-04-20 16:53:20", status: 0>]
Again, everything looks good, except now we have 2 orphan NextAction records - IDs #4 and #5.
Any ideas? Thanks so much!
It's because of the next_action in the factory :next_actions_order, which creates an additional next_action...
I would rewrite the next_action factory using
after(:build) do |next_action, evaluator|
next_action.orders << build(:order)
end
or
after(:build) do |next_action, evaluator|
next_action.orders << build_list(:order, evaluator.orders_count)
end
if you need more than one.
This way the entire chain is created at once with all cross references filled in as they should! (and without doubles!)

Rspec new expectation syntax

I've the following rspec unit test:
require 'spec_helper'
describe Article do
describe ".recents" do
it "includes articles created less than one week ago" do
article = Article.create(created_at: Date.today - 1.week + 1.second)
expect(Article.recents).to eql([article])
end
it "excludes articles published at midnight one week ago" do
article = Article.create!(:created_at => Date.today - 1.week)
expect(Article.recents).to be_empty
end
end
end
and the Articlemodel:
class Article < ActiveRecord::Base
attr_accessible :description, :name, :price, :created_at
scope :recents, where('created_at <= ?', 1.week.ago)
end
when I run my tests I get:
1) Article.recents includes articles created less than one week ago
Failure/Error: expect(Article.recents).to eql([article])
expected: [#<Article id: 60, name: nil, description: nil, price: nil, created_at: "2012-11-14 00:00:01", updated_at: "2012-11-21 10:12:33", section_id: nil>]
got: [#<Article id: 60, name: nil, description: nil, price: nil, created_at: "2012-11-14 00:00:01", updated_at: "2012-11-21 10:12:33", section_id: nil>]
(compared using eql?)
Diff:#<ActiveRecord::Relation:0x007ff692bce158>.==([#<Article id: 60, name: nil, description: nil, price: nil, created_at: "2012-11-14 00:00:01", updated_at: "2012-11-21 10:12:33", section_id: nil>]) returned false even though the diff between #<ActiveRecord::Relation:0x007ff692bce158> and [#<Article id: 60, name: nil, description: nil, price: nil, created_at: "2012-11-14 00:00:01", updated_at: "2012-11-21 10:12:33", section_id: nil>] is empty. Check the implementation of #<ActiveRecord::Relation:0x007ff692bce158>.==.
# ./spec/models/article_spec.rb:7:in `block (3 levels) in <top (required)>'
Could someone please help me to figure out what's the error in my test?
It seems good for me.
You are comparing an activerecord relation (Article.recents) to an array ([article]), which is why the expectation is failing. (It looks like they are the same in the spec results because inspect converts the relation into an array before printing it out.)
Change your first expectation to this:
expect(Article.recents.to_a).to eql([article])

Monitoring process interference Factory's instance initialization

In my project, the user will have many items, which have an onshelf_at attribute default to DateTime.now at its creation.
# item.rb
class Item < ActiveRecord::Base
before_create :calculate_onshelf_time
default_scope :order => 'items.onshelf_at DESC'
def calculate_onshelf_time
self.onshelf_at = DateTime.now
end
end
In the user model test, I tried to convince myself the retrieved order is indeed items.onshelf_at DESC. So I made the following snippet, but the result turned out to be reverse. (namely [#item1, #item2])
# spec/models/user_spec.rb
before :each do
#user = User.create(#attr)
#item1 = Factory(:item, :owner=>#user, :onshelf_at => 2.days.ago, :created_at => 2.days.ago)
#item2 = Factory(:item, :owner=>#user, :onshelf_at => 1.day.ago, :created_at => 1.day.ago)
end
it "should have the right items in the right order" do
#user.items.should == [#item2, #item1]
end
I checked the console, and found that onshelf_at wasn't listening to the instance initialization of Factory Girl. In its stead, it followed before_create rule, and valued to the time when test was run!
Failure/Error: #user.items.should == [#item2, #item1]
expected: [#<Item id: 2, description: "this is an item", img_link: "http://www.example.com/photos/some_pic.jpg", category_id: 5, onshelf: true, created_at: "2011-11-20 11:19:15", updated_at: "2011-11-21 11:19:15", onshelf_at: "2011-11-21 11:19:15", owner_id: 1>, #<Item id: 1, description: "this is an item", img_link: "http://www.example.com/photos/some_pic.jpg", category_id: 5, onshelf: true, created_at: "2011-11-19 11:19:15", updated_at: "2011-11-21 11:19:15", onshelf_at: "2011-11-21 11:19:15", owner_id: 1>]
got: [#<Item id: 1, description: "this is an item", img_link: "http://www.example.com/photos/some_pic.jpg", category_id: 5, onshelf: true, created_at: "2011-11-19 11:19:15", updated_at: "2011-11-21 11:19:15", onshelf_at: "2011-11-21 11:19:15", owner_id: 1>, #<Item id: 2, description: "this is an item", img_link: "http://www.example.com/photos/some_pic.jpg", category_id: 5, onshelf: true, created_at: "2011-11-20 11:19:15", updated_at: "2011-11-21 11:19:15", onshelf_at: "2011-11-21 11:19:15", owner_id: 1>] (using ==)
How can I fix this?
A quick fix would be to add a condition to your calculate_onshelf_time method:
self.onshelf_at = DateTime.now if self.onshelf_at.nil?
But - you don't even need all this. If you can (that is, if you have control over the schema), replace the onshelf_at attribute with a created_at column, which will automatically be set by Rails at the time of creation. If you're using migrations:
create_table :foo do |t|
# ...
t.timestamps
end
will add created_at and updated_at timestamps to the model.

Rails ActiveRecord :counter_cache not updated if assocation not set up before create. Intentional?

I've implemented a belongs_to relation with :counter_cache => true and I notice that the counter cache does not get updated if the relation was not set up before the initial save.
For instance, say a company has_many employees. If I do
company.employees << Employee.new(:name => "Joe")
The counter gets updated correctly but if I do
company.employees << Employee.create(:name => "Joe")
The counter remains unchanged.
For more details, here are the models:
class Employee < ActiveRecord::Base
belongs_to :company, :counter_cache => true
end
class Company < ActiveRecord::Base
has_many :employees
end
And here's a Rails Console session that demonstrates this:
Loading development environment (Rails 3.0.5)
ruby-1.9.2-p180 :001 > company_a = Company.create(:name => "ACME")
=> #<Company id: 1, name: "ACME", created_at: "2011-07-22 01:31:39", updated_at: "2011-07-22 01:31:39", employees_count: 0>
ruby-1.9.2-p180 :002 > company_a.employees << Employee.new(:name => "Bob")
=> [#<Employee id: 1, company_id: 1, name: "Bob", created_at: "2011-07-22 01:31:59", updated_at: "2011-07-22 01:31:59">]
ruby-1.9.2-p180 :003 > company_a.reload
=> #<Company id: 1, name: "ACME", created_at: "2011-07-22 01:31:39", updated_at: "2011-07-22 01:31:39", employees_count: 1>
ruby-1.9.2-p180 :004 > company_a.employees << Employee.create(:name => "Joe")
=> [#<Employee id: 1, company_id: 1, name: "Bob", created_at: "2011-07-22 01:31:59", updated_at: "2011-07-22 01:31:59">, #<Employee id: 2, company_id: 1, name: "Joe", created_at: "2011-07-22 01:32:28", updated_at: "2011-07-22 01:32:28">]
ruby-1.9.2-p180 :005 > company_a.reload
=> #<Company id: 1, name: "ACME", created_at: "2011-07-22 01:31:39", updated_at: "2011-07-22 01:31:39", employees_count: 1>
The documentation does say that the counter is incremented/decremented when the object is created/destroyed but I was thinking it should monitor updates as well to be useful. Otherwise, say, moving employees between companies would quickly result in counters that are totally off.
Is this the expected behavior? If so, what's the rationale? And if not, am I doing something wrong? I tried this in Rails 3.0.5 and Ruby 1.9.2
Thanks!

Error with "to_sql" on Rails 3 Beta 4

I'm testing Rails 3 beta 4 on Ruby 1.9.2-head, and when I start a
console and do:
Game.first.to_sql
I get this error:
ArgumentError: wrong number of arguments (0 for 1)
I know it can find the Game record, because when I type:
Game.first
it returns:
=> #<Game id: 1, name: "Galaga", created_at: "2010-06-19 11:02:37",
updated_at: "2010-06-19 11:02:37">
What am I missing? I just want to make the to_sql work in a very simple
case.
.
When you run Game.first you are returning a Game object, not a ActiveRecord::Relation object as you are expecting.
To do what you're trying to do, you'll need to do:
Game.limit(1).to_sql
This lets you run it without to_sql and return the object as you expected it, although it will be in an array, which then you can run .first on it like you wanted anyways.
irb(main):004:0> Game.limit(1).to_sql
=> "SELECT `games`.* FROM `games` LIMIT 1"
irb(main):005:0> Game.limit(1).class
=> ActiveRecord::Relation
irb(main):006:0> Game.limit(1)
=> [#<Game id: 1, name: "Galaga", created_at: "2010-06-19 11:02:37", updated_at: "2010-06-19 11:02:37">]
irb(main):007:0> Game.limit(1).first
=> #<Game id: 1, name: "Galaga", created_at: "2010-06-19 11:02:37", updated_at: "2010-06-19 11:02:37">
When you dig into the source, when you run .first on an ActiveRecord::Relation it runs the following (which is the same as I showed you):
def find_first
if loaded?
#records.first
else
#first ||= limit(1).to_a[0]
end
end

Resources