Why group calculation fields do not show up in que

2019-08-15 14:00发布

问题:

I have query like this: query = Link.select('url, max(created_at) as created_at, count(*) as url_count').group(:url).order('url_count desc, created_at asc')

Sample results of query.results.first:

2.2.0 :002 > query.first
 => #<Link id: nil, url: "http://1", created_at: "2015-03-10 16:43:54"> 

Why there is no url_count here, even though I know it is.

2.2.0 :003 > query.first.url_count
 => 17 

回答1:

The count is there all along but the model to_s method does not know about it.

The to_s method which is used when your console logs the result from query.first is defined somewhere in activerecord and it uses the attributes defined for the model in the database. Since your attribute is only defined for this particular instance of Link not for the model Link.

I found this quite interesting. Below is a description of how the message displayed in your console is constructed. It starts out in the gem active_attr with these 3 methods displayed below:

def inspect
  attribute_descriptions = attributes.sort.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
  separator = " " unless attribute_descriptions.empty?
  "#<#{self.class.name}#{separator}#{attribute_descriptions}>"
end

# ...

def attributes
  attributes_map { |name| send name }
end

# ...

def attributes_map
  Hash[ self.class.attribute_names.map { |name| [name, yield(name)] } ]
end

the method attributes_names is defined in the gem activerecord

def attribute_names
  @attribute_names ||= if !abstract_class? && table_exists?
      column_names
    else
      []
    end
end

# ...

def column_names
  @column_names ||= @connection.columns(@table_name).collect { |c| c.name }
end

And that is why your count does not show up.

If you really want it to show up in your console you could override the inspect method and add it there.