Weird stuff: validate_uniqueness_of with :scope does not work

Running rails 2.3.8.

I have a two models defined like this

class Member
has_many :folders
before_save: create_default_folders

protected
def create_default_folders!
%w{Inbox Sent}.each do |folder|
unless self.folders.find_by_name(folder)
self.folders.create!(:name => folder, :deletable => false)
end
end
end
end

class Folder
belongs_to :member

folder names must be unique for each user

validates_uniqueness_of :name, :scope => [:member_id], :allow_blank
=> false,
:case_sensitive => false, :message => ‘already exists for this
member’
end

------ MembersController
def create
@member = Member.new(params[:member])

if @member.save
     ...
end

end

So as you can see, what I wish to get when I save a new Member are two
default folders colled (Inbox and Sent).
So I defined the after_save callback. I tested it in script/console
and it works whenever I build and save a Member.

However, as soon as I create a member through a controller-backed
form, the uniqueness validation gets tripped up. I get validation
error from my validates_uniqueness_of as “Folder already exists for
this member”. Which shouldn’t happen.

For some strange reason :scope gets ignored and thus uniqueness check
isn’t properly scoped by member_id…

The weird part is that it all works in script/console, but not via web
forms.

Any suggestions???

Thanks in advance!

On Sep 7, 11:55 am, Swartz [email protected] wrote:

Is there some odd interaction because you’re creating these folders
from a before_save (ie the member’s id has not yet been set)?

Fred

dont use the before_save use transactions that way it will roll back
both
actions if there is an error.
and dont use that function you have with the each and all use

find_or_create_by_name(name)

it does what you want.

On Tue, Sep 7, 2010 at 7:20 AM, Frederick C.
<[email protected]

That’s what I thought originally about id not being set… but why
does it work from script/console ?
That kind of puzzles me…

On Sep 7, 5:20 am, Frederick C. [email protected]
wrote:

On Sep 7, 11:55 am, Swartz [email protected] wrote:

Also note that I have to set at least one other folder attribute while
creating a folder ,
so this variant doesn’t help me much.

That code must’ve been 5th iteration of trying to get that call back
to work.

I’ve tried your suggested method.
I’ve so tried create/create!, save/save!.

Everything work from console.
That is I can do
m = Member.new
m.x = “value”
m.folders.find_or_create_by_name('folder_name")
m.save

It all work beautifully from console. I can test my validation, it
works.

But as soon as I do the same thing (create new Member) from controller
context via form params, the scoped validates_uniqueness_of does not
function as expected.


Swartz

I’ve created a brand new Rails 2.3.8 app.
No gems, nothing.

I created only the bare necessities:
Two models (Member and Folder)
one controller (MembersController with only new and create actions)
one view (new).

I can create one member with default folders as per my callback (the
very first one), but any subsequent members don’t get default folders
created for them.

But again, when I try the same thing from script/console everything
works (I create new member and, bam, two folders come into existence
as well)…

w t f…

watch this and see if ti helps,

http://railscasts.com/episodes/196-nested-model-form-part-1

check your attri_accesible, and check if you rae using a gem that uses
attr_protected, it appears you have a problem with mass assignment and
you
cant see from one controller the attribute that member_id from the
folder
controller i think you need to be able to , also note that with before
save
there is no member_id in the database to compare the validation with
thats
why i said you should use a transaction and create everything from the
member controller like this

Member.transaction do
@member.new(blah, blah)
@member.save!
params[:folder_name].nil? ? name= “Default” : name =
params[:folder_name]
@folder = Folder.find(:conditions =>{:name = name, :member_id=>
@member.id})

@folder ||= Folder.new(blah blah)
@folder.member = @member
@folder.save!
end

try that, the code inside the transaction will rollback if either to the
save fail and everything will go back to the its original state.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs