ActiveRecord::QueryMethods#select bug (3.2.0.rc1) #4208

Closed
dx7 opened this Issue Dec 27, 2011 · 12 comments

Comments

Projects
None yet
6 participants

dx7 commented Dec 27, 2011

Rails 3.1

Loading development environment (Rails 3.1.3)
ruby-1.9.3 irb> user = User.select(:email).first
 => #<User email: "rafaeldx7@..."> 
ruby-1.9.3 irb> user.respond_to? :created_at
 => true 
ruby-1.9.3 irb> user.created_at
 => nil

Rails 3.2

Loading development environment (Rails 3.2.0.rc1)
ruby-1.9.3 irb> user = User.select(:email).first
 => #<User email: "rafaeldx7@..."> 
ruby-1.9.3 irb> user.respond_to? :created_at
 => true 
ruby-1.9.3 irb> user.created_at
ActiveModel::MissingAttributeError: missing attribute: created_at
    from (irb):3
    from /Users/rafaeldx7/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.0.rc1/lib/rails/commands/console.rb:47:in `start'
    from /Users/rafaeldx7/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.0.rc1/lib/rails/commands/console.rb:8:in `start'
    from /Users/rafaeldx7/.rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.0.rc1/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

Doc: http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-select

jonleighton was assigned Dec 27, 2011

Contributor

tapajos commented Dec 27, 2011

Rafael,

Analyzing the test bellow I think that it isn't a bug. The problem is that the doc is outdated.

  def test_find_only_some_columns
    topic = Topic.find(1, :select => "author_name")
    assert_raise(ActiveModel::MissingAttributeError) {topic.title}
    assert_nil topic.read_attribute("title")
    assert_equal "David", topic.author_name
    assert !topic.attribute_present?("title")
    assert !topic.attribute_present?(:title)
    assert topic.attribute_present?("author_name")
    assert_respond_to topic, "author_name"
  end
Member

josevalim commented Dec 28, 2011

Not sure if I prefer the new behavior. /cc @jonleighton

josevalim closed this in b3490d8 Dec 28, 2011

Member

jonleighton commented Dec 28, 2011

Hmm, I need to look into this. I don't think the behaviour was actually changed intentionally.

jonleighton reopened this Dec 28, 2011

Contributor

bjeanes commented Dec 28, 2011

Unless I'm mistaken, the 3.2 behavior is actually more in line with older versions of Rails. The 2.3.2 app we run at work raises the ActiveModel::MissingAttributeError exception when trying to operate on a non-selected column. Perhaps this behavior was a regression in 3.1 or thereabouts that was fixed in 3.2?

@arunagw arunagw pushed a commit to arunagw/rails that referenced this issue Dec 28, 2011

@josevalim josevalim Merge pull request #4210 from tapajos/patch-1
Fix #4208
d547761
Member

jonleighton commented Dec 29, 2011

I can't actually reproduce this issue with the following script:

require 'active_record'

puts ActiveRecord::VERSION::STRING

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

ActiveRecord::Schema.define do
  create_table :users do |t|
    t.string :name
    t.integer :age
  end
end

class User < ActiveRecord::Base
end

User.create! name: "Bob", age: 20

u = User.select(:name).select("'foo' as lol").first
puts u.name
puts u.lol
puts u.age

master branch output:

4.0.0.beta
-- create_table(:users)
   -> 0.0285s
Bob
foo
bug4208.rb:22:in `<main>': missing attribute: age (ActiveModel::MissingAttributeError)

3.1.3 output:

3.1.3
-- create_table(:users)
   -> 0.0128s
Bob
foo
bug4208.rb:22:in `<main>': missing attribute: age (ActiveModel::MissingAttributeError)

3.0.11 output:

3.0.11
-- create_table(:users)
   -> 0.0768s
Bob
foo
bug4208.rb:22:in `<main>': missing attribute: age (ActiveModel::MissingAttributeError)

@rafaeldx7 can you provide me with more complete instructions to reproduce?

Member

jonleighton commented Dec 29, 2011

Closing this pending better repro steps.

dx7 commented Dec 29, 2011

My application has a different behavior with 3.1.3. But I run your code and get same output.

But we have an inconsistent behavior with attributes:

require 'active_record'

puts ActiveRecord::VERSION::STRING

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')

ActiveRecord::Schema.define do
  create_table :users do |t|
    t.string :name
    t.integer :age
  end
end

class User < ActiveRecord::Base
end

User.create! name: "Bob", age: 20

u = User.select(:name).select("'foo' as lol").first

puts "#respond_to?"
puts u.respond_to?(:id)
puts u.respond_to?(:name)
puts u.respond_to?(:lol)
puts u.respond_to?(:age)

puts "#methods"
p u.id
p u.name
p u.lol
p u.age

Output:

3.1.3
-- create_table(:users)
   -> 0.0045s

#respond_to?
true
true
true
true

#methods
nil
"Bob"
"foo"
bug4208.rb:31:in `<main>': missing attribute: age (ActiveModel::MissingAttributeError)
  • respond_to? always returns true.
  • u.id returns nil (id wasn't selected)
  • u.age raises error

It looks like an inconsistent behavior.

Member

jonleighton commented Dec 30, 2011

The id method is a special case.

dx7 commented Dec 30, 2011

The main problem is the method age raises error and respond_to?(:age) returns true.

Member

jonleighton commented Dec 30, 2011

well, it responds_to?(:age) because technically the method does exist, it just happens to raise an error when called. You can use has_attribute?(:age) as an alternative.

kidpollo commented Apr 2, 2013

@jonleighton @josevalim et all. What is the expected behavior here? It seems to me that respond_to? should work as expected. I had to implement a hacky hack in my fork of rabl (nesquena/rabl#432) It seems to me that the AR should act as an actual ORM its crazy that respond_to should answer to true

Member

jonleighton commented Apr 5, 2013

I'm not sure what I was thinking in my last comment. I think it would make sense for respond_to?(:age) to return false in this case, so I'll reopen.

jonleighton reopened this Apr 5, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment