Eduardo Yáñez Parareda
2006-Aug-16 11:46 UTC
[Rails] Create several models at once and validating
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 What am I doing wrong? -- Posted via http://www.ruby-forum.com/.
> > /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 > endThis 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: <%= error_messages_for ''team'' %> <%= error_messages_for ''user'' %> Max
Eduardo Yáñez Parareda
2006-Aug-17 07:06 UTC
[Rails] Re: Create several models at once and validating
> 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 > endBut 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. -- Posted via http://www.ruby-forum.com/.
You can ensure that the models are both valid, e.g. with .valid? first. -- Posted via http://www.ruby-forum.com/.
Eduardo Yáñez Parareda
2006-Aug-17 07:36 UTC
[Rails] Re: Create several models at once and validating
kris wrote:> You can ensure that the models are both valid, e.g. with .valid? first.Thanks, that''s the way I resolved it, just now I was going to post it. -- Posted via http://www.ruby-forum.com/.
You can call validation first, and proceed to saving only if everything validates: if @user.valid? && @team.valid? @user.save(false) @team.save(false) end the ''valid?'' method does what you''d expect; the ''false'' paramter to the save method means "don''t do validation while saving" (since by the time you get to the save statement, the validation has already passed). Cheers, B Gates 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. __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
Mark Reginald James
2006-Aug-17 14:18 UTC
[Rails] Re: Create several models at once and validating
B Gates wrote:> You can call validation first, and proceed to saving > only if everything validates: > > if @user.valid? && @team.valid? > @user.save(false) > @team.save(false) > endThe only potential problem with this code is that you won''t get any @team error messages in the view if @user fails to validate. Instead you''d have to write: valid_team = @team.valid? if @user.valid? && valid_team -- We develop, watch us RoR, in numbers too big to ignore.