Firstly, don't have a current_ducks_listed attribute in the database,
just use @user.ducks.count. Then have a validation in the Duck model
that prevents the duck from being saved if its owner already has his
max allowance.
Colin
> For the sake of example let's say you have an application
> where users list their ducks for sale.
Viaduct? Vi-a no chicken? ;-)
> It's best to prevent the user from
> adding a duck if he has reached his limit. This introduces a chunk
> of logic whose place isn't quite clear. Let's put it in the controller:
>
> def new
I think you're on the right track having a *warning* show up in
ducks_controller#new. If, as Colin suggested, you have the *model*
check for excessive ducks as well, #create shouldn't need any
alterations from the standard scaffold-generated style. (At least,
not for this reason.) It will make the save fail, detected by
#create, which will just render #new again, with the errors carried by
@duck.
> Bearing in mind I'm two weeks into my Rails and Ruby studies,
You're showing a very good grasp of the concepts for only two weeks
in! Well done!
-Dave
--
Dave Aronson: Available Cleared Ruby on Rails Freelancer
(NoVa/DC/Remote) -- see www.DaveAronson.com, and blogs at
www.Codosaur.us, www.Dare2XL.com, www.RecruitingRants.com
It would probably just annoy people if they were not told until they'd
entered all their "new duck" requirements that they'd reached their
limit. So I'd also keep a permissions-type check in the controller
too. As Colin says the code to check for this is in the model, so can
be re-used by the permissions check and the validation.
class DucksController < AR:Base
before_filter :check_duck_limit, :only => [:new, :create]
def new
@duck = Duck.new
end
private
def check_duck_limit
flash[notice: "You have reached your limit. Upgrade your plan."]
if current_user.reached_duck_limit?
end
end
class User < AR:Base
validate :has_duck_availability
def reached_duck_limit?
self.ducks.count >= self.max_number_of_ducks
end
# in case a user can not yet have a plan, it's handy to make sure
it exists, and return a safe value
def max_number_of_ducks
plan ? plan.max_number_of_ducks || 0 : 0
end
private
def has_duck_availability
errors.add(:duck_count, "has been reached") if reached_duck_limit?
end
end
PS you don't need to assign "current_user" to an instance variable -
just use current_user ;-)
PPS Your current code alerts when the limit is exceeded, rather than reached
Not really that tricky.. business logic *always* belongs in the model ;-)
The problem sometimes comes in deciding what is business logic and what is not.
Colin