我想为以下内容实现服务器端验证: 只要订阅数量不超过此发布的点数,就只能创建特定发布的订阅。
class Cposting < ActiveRecord::Base
belongs_to :user
has_many :subscriptions,
foreign_key: "post_id",
dependent: :destroy
...
def spots_left #returns the number of places left in this class
self.spots.to_i - Subscription.where(post_id: self.id).count.to_i
end
...
end
在订阅模型中,我尝试调用spots_left方法来确定新订阅所属的Cposting是否还有剩余点。
class Subscription < ActiveRecord::Base
belongs_to :subscriber, class_name: "User"
belongs_to :post, class_name: "Cposting"
...
validate :class_not_full
def class_not_full
Cposting.find_by(id: self.post_id).spots_left > 0
end
end
在Subscription模型上运行测试返回了nil错误
NoMethodError: undefined method `spots_left' for nil:NilClass
似乎我不能使用find_by,find或where方法指向此Cposting。
我想知道如何引用属于正在验证的订阅的Cposting,或者实现此验证的替代方法。
由于
编辑添加测试
require 'test_helper'
class SubscriptionTest < ActiveSupport::TestCase
def setup
@cposting = cpostings(:one) #has one spot
@customer = users(:customer)
@customer2 = users(:customer2)
@subscription = Subscription.new(post_id: @cposting.id, subscriber_id: @customer.id)
end
...
test "subscriptions cannot exceed spots" do
@subscription.save
assert @cposting.subscriptions.count == @cposting.spots
@subscription2 = Subscription.new(post_id: @cposting.id, subscriber_id: @customer2.id)
assert_not @subscription2.valid?
end
end
正在运行rake test TEST=test/models/subscription_test.rb
1) Failure:
SubscriptionTest#test_subscriptions_cannot_exceed_spots [/~/test/models/subscription_test.rb:37]:
Expected true to be nil or false
5 runs, 7 assertions, 1 failures, 0 errors, 0 skips
编辑2添加创建方法
class SubscriptionsController < ApplicationController
def create
@posting = Cposting.find(params[:post_id])
current_user.subscriptions.create(post_id: @posting.id)
flash[:success] = "Subscribed!"
redirect_to subscriptions_path
end
end
答案 0 :(得分:0)
利用rails关系。你不需要再次查询所有内容。
尝试以下方法:
class Cposting < ActiveRecord::Base
belongs_to :user
has_many :subscriptions,
foreign_key: "post_id",
dependent: :destroy
def spots_left
self.spots - self.subscriptions.count # i assume that spots is an integer db field
end
end
和
class Subscription < ActiveRecord::Base
belongs_to :subscriber, class_name: "User"
belongs_to :post, class_name: "Cposting"
validate :class_not_full
def class_not_full
post.spots_left > 0
end
end
创建订阅:
@cposting.build_subscription(subscriber: @customer2)
Rails为您提供了一系列可供选择的方法。你甚至不需要使用ID。只需使用关系。一般来说,当你坚持使用AR方法时,我发现Rails工作得更顺畅(在命名表时坚持使用rails约定是个好主意) 请仔细阅读this,它会为您提供很多帮助。
答案 1 :(得分:0)
如果测试没有通过,则通过添加nil检查和错误来修复nil错误。
validate :class_not_full
def class_not_full #checks if there are spots left for the posting
errors.add(:post, "posting is already full") unless !post.nil? && post.spots > post.subscriptions.count
end