9

tôi nhận được lỗi deprecation trên một nâng cấp lên đường ray 4.2.1, Modifying already cached Relation. The cache will be reset. Use a cloned Relation to prevent this warning.Nhân bản một mối quan hệ trong đường ray

Hành động Tôi đang cố gắng để chạy được số lượng người dùng theo tháng đã đăng nhập.

thử nghiệm của tôi chỉ đơn giản là:

get :page 
expect(response).to be_success 

điều khiển hành động:

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 

Mô hình người dùng

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 

Tôi nhận thấy rằng tôi đang chạy gần như cùng một truy vấn 12 lần nhưng với các thông số khác nhau. Phương pháp này được sử dụng ở nơi khác khi người dùng không được nhóm. Làm thế nào tôi có thể 'nhân bản' một mối quan hệ như được đề xuất trong cảnh báo không dùng nữa?

Tôi không muốn chỉ đơn giản là bỏ qua này khi nó đang lấp đầy màn hình của tôi trong khi thử nghiệm chạy, mà không phải là rất hữu ích

+0

Nó có thể không hữu ích, nhưng tôi đang phải đối mặt với cùng một vấn đề - không có tài liệu cho nhân bản quan hệ: ( – marcus3006

+0

bạn có sử dụng đá quý squeel nạp trong dự án của bạn? – marcus3006

+0

@ marcus3006 - vâng tôi – Yule

Trả lời

5

Trong trường hợp của tôi, đó là đá quý squeel tạo ra cảnh báo không dùng nữa. Một monkeypatch đơn giản sửa chữa cảnh báo.

module Squeel 
    module Adapters 
    module ActiveRecord 
     module RelationExtensions 

     def execute_grouped_calculation(operation, column_name, distinct) 
      super 
     end 

     end 
    end 
    end 
end 

Tôi không chắc chắn nếu nó phá vỡ hành vi squeel, nhưng nó hoạt động cho tôi. Dường như vấn đề với Rails 4.2.x kết hợp với squeel. Tôi cũng đã đẩy điều này vào bộ theo dõi vấn đề squeel https://github.com/activerecord-hackery/squeel/issues/374.

-2

Câu trả lời ngắn:

Bỏ qua nó. Thông báo phản đối đã bị xóa khỏi nhánh chính của đường ray. Rails 5 sẽ không phàn nàn về nó.

Long trả lời:

Các vấn đề sau/cam kết dường như đưa ra một ấn tượng rằng thông điệp deprecation đã được bổ sung do nhầm lẫn, và đã bị xóa:

Có thể đáng để thử mã của bạn với nhánh chính của đường ray.

+1

Thông báo phản đối này đã bị xóa khỏi nhánh chính của Rails vì Rails 5 sẽ ném một 'ImmutableRelation' thay vì in một tin nhắn, vì vậy câu trả lời này chính xác –

1

Edited

Trước hết mã của bạn hoạt. Nó không tăng ImmutableRelation hoặc hiển thị thông báo không dùng nữa chạy trên đường ray 4.2.1.

Mã trên hành động trang của bạn không cần sao chép một mối quan hệ, bởi vì mã tạo ra một mã mới trên mỗi bước tháng (với: User...). Có nó có 12 truy vấn, nhưng nó không phải là một vấn đề cho bạn.

Nó không quá quan trọng, nhưng bạn có hai lỗi chính tả tại câu hỏi. Mô hình của bạn phải thay đổi def number_first_logged_in(month) bằng def self.number_first_logged_in(month) và tên kiểu máy phải là User và không phải Model.

Tôi kiểm tra ở thanh điều khiển đường ray (trên Products thay vì User và sử dụng :created_at thay vì trường :first_logged_in_at), nhưng nó giống nhau và hoạt động tốt. Và tôi khá chắc chắn rằng nếu bạn bắt đầu một ứng dụng đường ray tươi 4.2.1 và sử dụng mã tại câu hỏi (với lỗi chính tả đã sửa) nó sẽ hoạt động.

[email protected] [[email protected]]: ~/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 

Nhưng, bạn gặp sự cố. Vấn đề này không liên quan đến API đường ray công cộng, vì nó không có phương pháp nào có thể làm tăng các lỗi này hoặc không dùng nữa. Nhóm Rails nói rằng bất kỳ phương thức công khai nào là #nodockhông phải là một phần của API công khai. Phần lớn các phương thức truy vấn (nếu không phải tất cả), có phương thức một cặp (code), thay đổi quan hệ (thay vì trả về bản sao) và làm tăng số lỗi InmutableRelation (hoặc thông báo không dùng nữa trên phiên bản trước). Các phương thức công khai này là #nodoc và không thuộc API đường ray công khai.

Việc cần làm? Thật không dễ dàng:

  1. tìm mã của bạn để biết các phương thức này, có thể là bản vá khỉ được thực hiện trên AR.
  2. kiểm tra đá quý bạn đang sử dụng. Có lẽ, bắt đầu một ứng dụng mới với mã làm việc, và thêm tất cả các đá quý bạn có trong ứng dụng mục tiêu của bạn, và nếu không thành công, dùng thử và loại bỏ lỗi đá quý cho đến khi nó hoạt động trở lại.

Tôi đề cập đến các phương pháp bang, nhưng nó cũng đúng với phương pháp sửa đổi quan hệ (điều này không thể được thực hiện bởi API công cộng). Bạn phải tìm miếng vá khỉ hoặc mở rộng trên quan hệ.

Điều đó phải đủ để khắc phục vấn đề.

Tôi đọc bình luận của bạn, và tôi đã nhận điểm, tôi nghĩ rằng các tùy chọn này:

  • Rails cơ sở dữ liệu độc lập hoạt động thông qua AREL. Và arel không có các phương thức để làm việc trực tiếp với các hàm db (tháng của trường ngày). Bạn có thể mở rộng arel và viết nó, nhưng bạn cần phải viết một cho PostgreSql một cho MySql khác cho Sqlite. (Quá đắt, tại số này điểm)

  • Nếu bạn sử dụng cùng một trình quản lý db trên dev/test/prod bạn có thể sử dụng một truy vấn văn bản một phần như tôi đã đề xuất. (Điều này không giống như bạn)

  • Giữ 12 câu truy vấn (Tôi nghĩ rằng bạn có thể sống với một này)

  • Thêm một lĩnh vực dành riêng cho group_by (year_month có thể).(Rất rigig, khó để thay đổi)

tôi giữ câu trả lời cũ, bởi vì: Nếu tôi là bạn, tôi sẽ làm một cái gì đó như thế này:

class User 
    scope :for_current_year, -> { where(created_at: Date.today.beginning_of_year..Date.today.end_of_year } 
end 

action trang điều khiển bạn có thể sử dụng: (tôi đề nghị sử dụng mà)

User.for_current_year 
    .group("date_trunc('month', users.created_at)", "usergroup").count 

nào trả về một băm với mô hình này: (thêm đếm here)

{ 
    [<first date of the month of created_at>, <usergroup>] => count, 
    ... 
} 

Nhưng nếu bạn muốn nhận được cùng một số @months trước đây, bạn phải lập bản đồ kết quả bằng ruby.

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 

Note1: mã này làm việc cho PostgreSQL vì nó sử dụng các chức năng date_trunc(...), nếu bạn cần phải sử dụng với MySql bạn muốn sử dụng month(users.created_at) để thay thế. Khi ánh xạ với MySql bạn cần sử dụng k[0] thay vì k[0].month.

Lưu ý2: Cuộc gọi group có các tham số riêng biệt cho các trường của nó, bởi vì bạn muốn có hai giá trị trên khóa của hàm băm được trả về.

+0

Và nếu môi trường thử nghiệm/dev/prod của tôi chạy trên các cơ sở dữ liệu khác nhau thì điều này có vẻ hơi lộn xộn, tôi cũng đang tìm kiếm câu trả lời chứ không phải giải pháp thay thế. hoàn toàn khác – Yule

0

tôi thấy hai giải pháp khả thi:

Bạn có thể xóa bộ nhớ cache giữa các truy vấn: ActiveRecord::Base.connection.query_cache.clear từClearing active Record Cache

Bạn có thể sử dụng .dup nhân bản mối quan hệ trước khi bạn vận dụng nó, do đó bạn không làm mất hiệu lực bộ nhớ cache.

Các vấn đề liên quan