Helpex - Trao đổi & giúp đỡ Đăng nhập
22

Tôi muốn giới hạn số lượng mục trong một hiệp hội. Tôi muốn đảm bảo Người dùng không có nhiều hơn X Thứ. Câu hỏi này đã được hỏi trước đây và giải pháp có logic trong đứa trẻ:

Giải pháp được cung cấp (cho vấn đề tương tự):

class User < ActiveRecord::Base
  has_many :things, :dependent => :destroy
end

class Thing <ActiveRecord::Base
  belongs_to :user
  validate :thing_count_within_limit, :on => :create

  def thing_count_within_limit
    if self.user.things(:reload).count >= 5
      errors.add(:base, "Exceeded thing limit")
    end
  end
end

Mã cứng "5" là một vấn đề. Giới hạn của tôi thay đổi dựa trên phụ huynh. Bộ sưu tập Những thứ biết giới hạn của nó liên quan đến Người dùng. Trong trường hợp của chúng tôi, Người quản lý có thể điều chỉnh giới hạn (Số thứ) cho mỗi Người dùng, vì vậy Người dùng phải giới hạn bộ sưu tập của mình. Chúng tôi có thể yêu cầu thing_count_within_limit yêu cầu giới hạn từ người dùng của nó:

if self.user.things(:reload).count >= self.user.thing_limit

Tuy nhiên, đó là rất nhiều sự xem xét nội tâm của người dùng từ Thing. Nhiều cuộc gọi đến người dùng và đặc biệt, đó (:reload)là những dấu hiệu đỏ đối với tôi.

Suy nghĩ về một giải pháp phù hợp hơn:

Tôi nghĩ has_many :things, :before_add => :limit_thingssẽ hiệu quả, nhưng chúng ta phải nêu ra một ngoại lệ để ngăn chặn chuỗi . Điều đó buộc tôi phải cập nhật things_controller để xử lý các ngoại lệ thay vì quy ước rails của if valid?hoặc if save.

class User
  has_many :things, :before_add => limit_things

  private
  def limit_things
    if things.size >= thing_limit
      fail "Limited to #{thing_limit} things")
    end
  end
end

Đây là Rails. Nếu tôi phải làm việc chăm chỉ như thế này, có lẽ tôi đang làm sai điều gì đó.

Để thực hiện việc này, tôi phải cập nhật mô hình mẹ, bộ điều khiển của con VÀ tôi không thể tuân theo quy ước? Tui bỏ lỡ điều gì vậy? Tôi có đang lạm dụng has_many, :before_addkhông? Tôi đã tìm kiếm một ví dụ bằng cách sử dụng: before_add, nhưng không thể tìm thấy bất kỳ ví dụ nào.

Tôi đã nghĩ đến việc chuyển xác thực cho Người dùng, nhưng điều đó chỉ xảy ra trên Lưu / cập nhật Người dùng. Tôi không thấy có cách nào để sử dụng nó để ngăn việc thêm Thứ.

Tôi thích một giải pháp hơn cho Rails 3 (nếu điều đó quan trọng đối với vấn đề này).

22 hữu ích 5 bình luận 13k xem chia sẻ
28

Vì vậy, nếu bạn muốn có một giới hạn khác nhau cho mỗi người dùng, bạn có thể thêm things_limit: integer vào Người dùng và thực hiện

class User
  has_many :things
  validates_each :things do |user, attr, value|
   user.errors.add attr, "too much things for user" if user.things.size > user.things_limit
  end
end

class Thing
  belongs_to :user
  validates_associated :user, :message => "You have already too much things."
end

với mã này, bạn không thể cập nhật user.things_limit xuống một con số thấp hơn tất cả những thứ mà anh ta đã có, và tất nhiên nó hạn chế người dùng tạo ra những thứ bởi user.things_limit của anh ta.

Ví dụ ứng dụng Rails 4:

https://github.com/senayar/user_things_limit

28 hữu ích 2 bình luận chia sẻ
6

Việc xác thực số lượng hiện tại khiến số lượng trở nên lớn hơn giới hạn sau khi quá trình lưu hoàn tất. Cách duy nhất tôi đã tìm ra để ngăn quá trình tạo xảy ra là xác thực rằng trước khi tạo, số lượng thứ ít hơn giới hạn.

Điều này không có nghĩa là việc xác thực số lượng trong mô hình Người dùng là không hữu ích, nhưng làm như vậy không ngăn User.things.createviệc được gọi vì bộ sưu tập số lượng của người dùng hợp lệ cho đến khi đối tượng Thing mới được lưu, sau đó trở thành không hợp lệ sau khi lưu.

class User
  has_many :things
end

class Thing
  belongs_to :user
  validate :on => :create do
    if user && user.things.length >= thing_limit
      errors.add(:user, :too_many_things)
    end
  end
end
6 hữu ích 0 bình luận chia sẻ
4

hãy thử cái này, giống như chuỗi:

class User < ActiveRecord::Base
  has_many :things, :dependent => :destroy
  validates :things, length: {maximum: 4}
end
4 hữu ích 0 bình luận chia sẻ
3

Tôi nghĩ rằng tôi sẽ gọi điện ở đây. Có vẻ như hầu hết các câu trả lời ở đây đều thất bại trong điều kiện chủng tộc. Tôi đang cố gắng giới hạn số lượng người dùng có thể đăng ký ở một mức giá nhất định trong ứng dụng của chúng tôi. Kiểm tra giới hạn trong Rails có nghĩa là 10 đăng ký đồng thời có thể vượt qua, ngay cả khi nó vượt quá giới hạn mà tôi đang cố gắng thiết lập.

Ví dụ: giả sử tôi muốn giới hạn số lượng đăng ký không quá 10. Giả sử rằng tôi đã có 5 người dùng đã đăng ký. Cũng giả sử rằng 6 người dùng mới cố gắng đăng ký cùng một lúc. Trong 6 chủ đề khác nhau, Rails đọc số lượng slot còn lại và nó sẽ nhận được câu trả lời 5. Điều này vượt qua xác thực. Rails sau đó cho phép tất cả các đăng ký đi qua và tôi có 11 đăng ký. : /

Đây là cách tôi giải quyết vấn đề này:

def reserve_slot(price_point)
  num_updated = PricePoint.where(id: price_point.id)
    .where('num_remaining <= max_enrollments')
    .update_all('num_remaining = num_remaining + 1')

  if num_updated == 0
    raise ActiveRecord::Rollback
  end
end

Sử dụng phương pháp này, tôi không bao giờ cho phép đăng ký nhiều hơn max_enrollments, ngay cả khi ứng dụng đang tải. Điều này là do việc xác nhận và tăng dần được thực hiện trong một hoạt động cơ sở dữ liệu nguyên tử, đơn lẻ. Xin lưu ý rằng tôi luôn gọi phương thức này từ bên trong một giao dịch, vì vậy nó sẽ hoạt động trở lại khi không thành công.

3 hữu ích 0 bình luận chia sẻ
1

Trong Rails 4, có lẽ phiên bản trước đó bạn chỉ có thể xác nhận về giá trị của counter_cache.

class User
  has_many :things
  validates :things_count, numericality: { less_than: 5 }
end

class Thing
  belongs_to :user, counter_cache: true
  validates_associated :user
end

lưu ý rằng tôi đã sử dụng :less_than:less_than_or_equal_tosẽ cho phép things_count6vì nó được xác nhận sau khi cập nhật truy cập bộ nhớ cache.

Nếu bạn muốn đặt giới hạn trên cơ sở mỗi người dùng, bạn có thể tạo một things_limitcột để so sánh động với giá trị giới hạn mà bạn đã đặt.

validates :things_count, numericality: { less_than: :things_limit }
1 hữu ích 2 bình luận chia sẻ
0

Bạn đã điều tra như thế nào khi sử dụng accept_nested_attributes_for?

accept_nested_attributes_for: things,: limit => 5

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Điều đó nói rằng, tôi nghĩ accept_nested_attributes_for dường như chỉ thích hợp cho một số loại tình huống nhất định. Ví dụ: nếu bạn đang tạo một API dòng lệnh, tôi nghĩ đó là một giải pháp khá tệ. Tuy nhiên, nếu bạn có một biểu mẫu lồng nhau, nó hoạt động đủ tốt (hầu hết thời gian).

0 hữu ích 1 bình luận chia sẻ
0

Bạn có thể thử validates_length_ofvalidates_associated:

class Client < ActiveRecord::Base

  has_many :orders
  validates :orders, :length => { :maximum => 3 }

end

class Order < ActiveRecord::Base

  belongs_to :client
  validates_associated :client

end

Một thử nghiệm nhanh cho thấy rằng valid?phương pháp này hoạt động như mong đợi, nhưng nó không ngăn bạn thêm các đối tượng mới.

0 hữu ích 1 bình luận chia sẻ
-4

Bạn nên thử điều này.

class Thing <ActiveRecord::Base
  belongs_to :user
  validate :thing_count, :on => :create

  def thing_count
      user = User.find(id)
      errors.add(:base, "Exceeded thing limit") if user.things.count >= 5
  end
end
-4 hữu ích 2 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ ruby-on-rails activerecord callback associations , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading