Ruby on rails 在rails中克隆关系

Ruby on rails 在rails中克隆关系,ruby-on-rails,rails-activerecord,rails-4-2-1,adequate-record,Ruby On Rails,Rails Activerecord,Rails 4 2 1,Adequate Record,我在升级到rails 4.2.1,修改已经缓存的关系时遇到了弃用错误。缓存将被重置。使用克隆的关系来防止此警告。 我尝试运行的操作会按月获取已登录的用户数 我的测试很简单: get :page expect(response).to be_success 控制器操作: def page @months = {} (0..11).each do |month| @months[month] = User.group(:usergroup).number_first_logged

我在升级到rails 4.2.1,
修改已经缓存的关系时遇到了弃用错误。缓存将被重置。使用克隆的关系来防止此警告。

我尝试运行的操作会按月获取已登录的用户数

我的测试很简单:

get :page
expect(response).to be_success
控制器操作:

def page
  @months = {}
  (0..11).each do |month|
     @months[month] = User.group(:usergroup).number_first_logged_in(Date.new(Date.today.year,month+1, 1))
  end
end
用户模型

class Model < ActiveRecord::Base
   ...
   def number_first_logged_in(month)
     where(first_logged_in_at: month.beginning_of_month..month.end_of_month).count
   end
end
类模型
我意识到我运行了12次几乎相同的查询,但参数不同。当用户未分组时,此方法在其他地方使用。如何按照弃用警告中的建议“克隆”关系

我不想简单地忽略这一点,因为它在运行测试时填满了我的屏幕,这不是很有帮助

简短回答:

别理它。已从rails的主分支中删除了弃用消息。Rails 5不会对此抱怨

长答覆:

以下问题/提交似乎给人一种印象,即弃用消息是错误添加的,已被删除:


可能值得使用rails的主分支尝试您的代码。

已编辑

首先,也是最重要的您的代码可以运行。它不会引发
ImmutableRelation
或显示运行在rails 4.2.1上的弃用消息

页面上的代码操作不需要克隆关系,因为它会在每个月步骤上创建一个新的关系(使用:
User…
)。是的,它有12个查询,但这不是你的问题

这不太重要,但是你在这个问题上有两个打字错误。您的型号必须使用
def self.number\u first\u logged\u(月)
更改
def number\u first\u logged\u(月)
,型号名称必须是
User
而不是
model

我在rails控制台(通过
产品
而不是
用户
,并使用
:created_at
而不是
:first_logged_in_at
字段)测试它,但它是相同的,工作正常。我非常确信,如果你启动一个全新的rails 4.2.1应用程序,并在问题处使用代码(纠正了拼写错误),它会工作的

alejandro@work-one [ruby-2.1.1@rails42]: ~/rails/r42example 
[09:14:04] $ rails c
Loading development environment (Rails 4.2.1)
~/rails/r42example (development) > @m = {};(0..11).each {|m| @m[m] = Product.group(:name).number_first_logged_in(Date.new(Date.today.year,m+1, 1)) }
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-01-01' AND '2015-01-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-02-01' AND '2015-02-28') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-03-01' AND '2015-03-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-04-01' AND '2015-04-30') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-05-01' AND '2015-05-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-06-01' AND '2015-06-30') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-07-01' AND '2015-07-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-08-01' AND '2015-08-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-09-01' AND '2015-09-30') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-10-01' AND '2015-10-31') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-11-01' AND '2015-11-30') GROUP BY "products"."name"
   (0.1ms)  SELECT COUNT(*) AS count_all, name AS name FROM "products" WHERE ("products"."created_at" BETWEEN '2015-12-01' AND '2015-12-31') GROUP BY "products"."name"
=> 0..11
但是,您有一个问题。此问题与公共rails API无关,因为它没有可能引发这些错误或弃用的方法。Rails团队表示,任何
#nodoc
公共方法都不是公共API的一部分。大多数查询方法(如果不是全部的话)都有一个pair-bang方法(),它修改关系(而不是返回克隆)并引发
InmutableRelation
错误(或以前版本中的弃用消息)。这些public方法是
#nodoc
,不是public rails API的一部分

怎么办?不容易:

  • 在代码中搜索这些bang方法,也许是在AR上完成的猴子补丁
  • 检查你正在使用的宝石。也许,在代码正常的情况下启动一个新的应用程序,并在目标应用程序中添加所有gem,如果失败,则反复尝试删除gem,直到它再次正常工作
  • 我指的是bang方法,但对于修改关系的方法也是如此(公共API无法做到这一点)。你们必须寻找猴子补丁或延伸关系

    这必须足以解决问题

    我读了你的评论,我明白了,我认为这些选项:

    • Rails数据库独立性通过arel工作。而阿雷尔没有 方法直接使用db函数(日期字段的月份)。 您可以扩展arel并编写它,但您需要为arel编写一个 PostgreSql一个用于MySql,另一个用于Sqlite。(这个价格太贵了 (点)

    • 如果在dev/test/prod上使用相同的db管理器,则可以使用部分 我建议的文本查询。(这不喜欢你)

    • 保留12个查询(我想你可以接受这个)

    • 在组中添加一个专用字段(可以是年或月)。(非常严格, (难以改变)

    我保留了老答案,因为:如果我是你,我会这样做:

    class User
      scope :for_current_year, -> { where(created_at: Date.today.beginning_of_year..Date.today.end_of_year }
    end
    
    在控制器页面上,您可以使用以下操作:(我建议使用该操作)

    它返回具有以下模式的哈希:(计数的更多)

    注1:此代码适用于PostgreSQL,因为它使用函数
    date\u trunc(…)
    ,如果需要与MySql一起使用,则需要使用
    month(users.created\u at)
    。使用MySql进行映射时,需要使用
    k[0]
    而不是
    k[0].month


    注意2:
    group
    调用对其字段有单独的参数,因为您希望在返回的哈希的键上有两个值。

    我看到两种可能的解决方案:

    您可以清除查询之间的缓存:
    ActiveRecord::Base.connection.query\u cache.clear


    您可以使用
    .dup
    在操作关系之前克隆它,这样就不会使缓存无效。

    在我的例子中,是squel gem产生了弃用警告。一个简单的monkeypatch修复了这个警告

    module Squeel
      module Adapters
        module ActiveRecord
          module RelationExtensions
    
            def execute_grouped_calculation(operation, column_name, distinct)
              super
            end
    
          end
        end
      end
    end
    

    我不确定它是否会破坏“静默”行为,但它对我有效。Rails 4.2.x与squeel的结合似乎有问题。我还把这个推到了静噪问题跟踪程序中

    此弃用消息已从Rails的主分支中删除,因为Rails 5将抛出一个
    ImmutableRelation
    ,而不是打印消息,因此此答案完全错误。它可能没有帮助,但我面临相同的问题-没有克隆关系的文档:(您是否使用项目中加载的squel gem?@marcus3006-是的,我的答案可能会对您有所帮助,如果我的测试/开发/产品环境运行在不同的数据库上会怎么样?这感觉有点混乱。我还想找一个
    {
      [<first date of the month of created_at>, <usergroup>] => count,
      ...
    }
    
    def page
      @months = User.for_current_year
        .group("date_trunc('month', users.created_at)", "usergroup").count
        .map { |k,v| {k[0].month => {k[1] => v}} }
    end
    
    module Squeel
      module Adapters
        module ActiveRecord
          module RelationExtensions
    
            def execute_grouped_calculation(operation, column_name, distinct)
              super
            end
    
          end
        end
      end
    end