I have two models User and Team. Also I have a register form where the
new
user fill in her data and choose a name for a Team.
Well, in the user model there are several validations which work fine,
but
team model also have a validation for a uniqueness name that doesn’t
fire up
when she gives an existent team’s name.
This is the flow it follows:
/user/new -> it shows a form to fill user’s data and a team’s name ->
Create ->
UserController
def create @user = User.create(params)
if request.post? and @user.save
…
end
end
User
validates_uniqueness_of :username <— THIS WORKS FINE
def self.create
user = User.new(params[:user])
team = Team.new(params[:team])
user.team = team
user
end
Team
validates_uniqueness_of :name <— THIS DOESN’T WORK
User
validates_uniqueness_of :username <— THIS WORKS FINE
def self.create
user = User.new(params[:user])
team = Team.new(params[:team])
user.team = team
user
end
This is bad. Your model should not be dependent on the View or the
Controller - by using the params hash in your model code, you are
restricting your model to only work in a request context. This
prevents you from using User.create anywhere but from a controller
that is called from a form that has a :users parameter set. You are
also changing the semantics of the create method, which by convention
performs a save of the model.
You should also be wrapping the two save operations in a transaction.
Should be rewritten as:
class UserController
def create @user = User.new(params[:user]) @team = Team.new(params[:team])
User.transaction do
success = @user.save
success &= @team.save
if success
flash[:notice] = ‘User was successfully created.’
redirect_to :action => ‘list’
else
render :action => ‘new’
end
end
end
…
The “success” stuff is there so that both models get a chance to
validate themselves (which happens on save).
In your view, you will need to also add error output for the @team
model instance. By default, the scaffolding assumes that there is a
single model object for a controller and view:
This is bad. Your model should not be dependent on the View or the
Controller - by using the params hash in your model code, you are
restricting your model to only work in a request context.
Yes, you’re absolutely right, I’ve already change it.
class UserController
def create @user = User.new(params[:user]) @team = Team.new(params[:team])
User.transaction do
success = @user.save
success &= @team.save
if success
flash[:notice] = ‘User was successfully created.’
redirect_to :action => ‘list’
else
render :action => ‘new’
end
end
end
But I don’t want this behaviour. I forgot to mention that User and Team
are related:
User Team
has_one :team <--------------> belongs_to :user
Thus I did @user.team = @team then @user.save that saves my user and the
related team too.
But if I do @user.save and then @team.save, whether validations on team
failed,
the user is created but team doesn’t and I want non of them to be saved.