br3*_*3nt 1 ruby-on-rails arel ruby-on-rails-4
NoMethodError: undefined method relation' for <Arel::Nodes::NamedFunction:0x7633>当我尝试按命名函数的结果进行分组时,我得到了。
class Appointment < ActiveRecord::Base
scope :group_by_date, -> { group(date_column) }
def self.date_column
Arel::Nodes::NamedFunction.new(:date, [Appointment.arel_table[:start_time]], 'date')
end
end
Appointment.group_by_date.count
# results in NoMethodError: undefined method `relation' for #<Arel::Nodes::NamedFunction:0x7633>
Run Code Online (Sandbox Code Playgroud)
这看起来完全合理,所以我不确定为什么会产生错误。我很确定这在早期版本的 Rails 中是可能的,如这个 SO 答案所示。
我期望得到类似于以下 sql 的内容:
SELECT date(appointments.start_time) AS date, COUNT(appointments.*) AS count
FROM appointments
GROUP BY date(appointments.start_time)
Run Code Online (Sandbox Code Playgroud)
有办法让它发挥作用吗?有没有办法将其转换Arel::Nodes::NamedFunction为Arel::Attributes::Attribute
这显然是一个幼稚的解决方案尝试(它不起作用):
function = Arel::Nodes::NamedFunction.new('date', [Appointment[:start_time]])
attr = Arel::Attributes::Attribute.new(function)
Appointment.group(attr).to_sql
# NoMethodError: undefined method `table_alias' for #<Arel::Nodes::NamedFunction:0x4b8>
Run Code Online (Sandbox Code Playgroud)
我真的不想回到 using ,Appointment.group( 'date(appointments.start_time)' )因为我做了很多范围合并和连接,字符串会造成严重破坏,因为它们并不总是作用于正确的表。
环境:rails (4.1.8)、activerecord (4.1.8)、arel (5.0.1.20140414130214)
这是一个棘手的问题。首先,您的 NamedFunction 定义有几个完全不明显的问题:首先,第一个参数必须是字符串,否则您会得到以下结果:
irb(main):040:0> User.group( Arel::Nodes::NamedFunction.new(:date, [User.arel_table[:created_at]], 'date') )
TypeError: no implicit conversion of Symbol into String
from /var/lib/gems/2.1.0/gems/arel-6.0.2/lib/arel/collectors/plain_string.rb:13:in `<<'
from /var/lib/gems/2.1.0/gems/arel-6.0.2/lib/arel/visitors/to_sql.rb:458:in `visit_Arel_Nodes_NamedFunction'
Run Code Online (Sandbox Code Playgroud)
其次,您需要删除第三个参数(别名),否则 Arel 会尝试将其推入 GROUP BY 子句中,并且您会收到错误(至少在 Postgres 中):
irb(main):045:0> User.group( Arel::Nodes::NamedFunction.new('date', [User.arel_table[:created_at]], 'date') )
User Load (4.9ms) SELECT "users".* FROM "users" GROUP BY date("users"."created_at") AS date
PG::SyntaxError: ERROR: syntax error at or near "AS"
LINE 1: ...".* FROM "users" GROUP BY date("users"."created_at") AS date
^
: SELECT "users".* FROM "users" GROUP BY date("users"."created_at") AS date
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "AS"
LINE 1: ...".* FROM "users" GROUP BY date("users"."created_at") AS date
^
: SELECT "users".* FROM "users" GROUP BY date("users"."created_at") AS date
from /var/lib/gems/2.1.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:596:in `async_exec'
Run Code Online (Sandbox Code Playgroud)
您没有注意到这些,因为您收到的错误实际上与.count调用有关;没有它,这现在实际上有效:
irb(main):066:0> nf = Arel::Nodes::NamedFunction.new('date', [User.arel_table[:created_at]])
=> #<Arel::Nodes::NamedFunction:0x9dc9ca0 @expressions=[#<struct Arel::Attributes::Attribute relation=#<Arel::Table:0xbdb689c @name="users", @engine=User(id: integer, name: string, age: integer, created_at: datetime, updated_at: datetime), @columns=nil, @aliases=[], @table_alias=nil, @primary_key=nil>, name=:created_at>], @alias=nil, @distinct=false, @name="date">
irb(main):067:0> User.group(nf).select(nf)
User Load (2.5ms) SELECT date("users"."created_at") FROM "users" GROUP BY date("users"."created_at")
=> #<ActiveRecord::Relation [#<User id: nil>]>
Run Code Online (Sandbox Code Playgroud)
那么,为什么不起作用.count呢?不幸的是,根据堆栈跟踪,这看起来像是一个错误。该count方法进入ActiveRelation::Calculations#execute_grouped_calculation并简单地走上了一条糟糕的道路。那里不支持处理来自 Arel 的 NamedFunction。
但是,您可以解决这个问题:
irb(main):017:0> User.group(nf).pluck('count(*)').first
(2.5ms) SELECT count(*) FROM "users" GROUP BY date("users"."created_at")
=> 1
Run Code Online (Sandbox Code Playgroud)
嗯是的。您可能想在 Rails 中为此打开一个问题。我个人建议您按字符串表达式进行分组,这样可以省去一些麻烦!
| 归档时间: |
|
| 查看次数: |
1328 次 |
| 最近记录: |