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
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.
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.
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)?
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
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.
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.
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)..