accepts_nested_attributes_for #185

emrekutlu opened this Issue Nov 15, 2011 · 12 comments

2 participants

class Author < ActiveRecord::Base
  belongs_to :publication, :polymorphic => true
  friendly_id :name, :use => :slugged
class Book < ActiveRecord::Base
  has_many :authors, :as => :publication
  accepts_nested_attributes_for :authors

I am using "4.0.0.beta14". I have a form for Book model which also can add multiple authors. Author model's slug column has an unique index.

When i try to add multiple authors whose name is same, all authors try to get the same slug, so a "Mysql2::Error: Duplicate entry" occurs.


"When i try to add multiple authors"

Thanks for the bug report. Can you show me code that shows me exactly how you're trying to do that? Also, please show me your whole stack trace, not just the error message.

I am more than happy to help you but if I have send you multiple messages to figure out what's going on in your code, or spend 30 minutes figuring out how to reproduce your problem, then I can't help you because I am literally too busy.


Ok, i'm sorry, you're right. I create a repository to reproduce the error.

I am using Rails 3.1. I try to explain it here in more detail.

class Author < ActiveRecord::Base
  extend FriendlyId
  belongs_to :publication, :polymorphic => true
  friendly_id :name, :use => :slugged
class Book < ActiveRecord::Base
  has_many :authors, :as => :publication
  accepts_nested_attributes_for :authors

I added a unique index for slug column.

In books controller:

def new
    @book =
    (1..3).each do

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @book }

I have a form for Book model, which i use to add a book title and author names. accepts_nested_attributes_for is used to add author names. For simplicity i just build 3 authors. So i have a form which has 4 fields, one for book title and 3 for author names.

When i try to add multiple authors with the same name, i got an exception.

SQLite3::ConstraintException in BooksController#create
column slug is not unique

Full trace:

activerecord (3.1.0) lib/active_record/connection_adapters/sqlite_adapter.rb:110:in `close'
activerecord (3.1.0) lib/active_record/connection_adapters/sqlite_adapter.rb:110:in `block in clear_cache!'
activerecord (3.1.0) lib/active_record/connection_adapters/sqlite_adapter.rb:110:in `each'
activerecord (3.1.0) lib/active_record/connection_adapters/sqlite_adapter.rb:110:in `clear_cache!'
activerecord (3.1.0) lib/active_record/connection_adapters/sqlite_adapter.rb:104:in `disconnect!'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:214:in `block in clear_reloadable_connections!'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:213:in `each'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:213:in `clear_reloadable_connections!'
activesupport (3.1.0) lib/active_support/core_ext/module/synchronization.rb:35:in `block in clear_reloadable_connections_with_synchronization!'
/home/emre/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
activesupport (3.1.0) lib/active_support/core_ext/module/synchronization.rb:34:in `clear_reloadable_connections_with_synchronization!'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:391:in `block in clear_reloadable_connections!'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:391:in `each_value'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:391:in `clear_reloadable_connections!'
activerecord (3.1.0) lib/active_record/connection_adapters/abstract/connection_specification.rb:123:in `clear_reloadable_connections!'
activerecord (3.1.0) lib/active_record/railtie.rb:84:in `block (3 levels) in <class:Railtie>'
activesupport (3.1.0) lib/active_support/callbacks.rb:404:in `_run_cleanup_callbacks'
activesupport (3.1.0) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (3.1.0) lib/action_dispatch/middleware/reloader.rb:72:in `rescue in call'
actionpack (3.1.0) lib/action_dispatch/middleware/reloader.rb:67:in `call'
rack (1.3.5) lib/rack/sendfile.rb:101:in `call'
actionpack (3.1.0) lib/action_dispatch/middleware/remote_ip.rb:48:in `call'
actionpack (3.1.0) lib/action_dispatch/middleware/show_exceptions.rb:47:in `call'
railties (3.1.0) lib/rails/rack/logger.rb:13:in `call'
rack (1.3.5) lib/rack/methodoverride.rb:24:in `call'
rack (1.3.5) lib/rack/runtime.rb:17:in `call'
activesupport (3.1.0) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.3.5) lib/rack/lock.rb:15:in `call'
actionpack (3.1.0) lib/action_dispatch/middleware/static.rb:53:in `call'
railties (3.1.0) lib/rails/engine.rb:455:in `call'
railties (3.1.0) lib/rails/rack/content_length.rb:16:in `call'
railties (3.1.0) lib/rails/rack/log_tailer.rb:14:in `call'
rack (1.3.5) lib/rack/handler/webrick.rb:59:in `service'
/home/emre/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service'
/home/emre/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run'
/home/emre/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'

Maybe request parameters will help:

 "book"=>{"title"=>"book title",
 "commit"=>"Create Book"}

I hope this helps.


Awesome, thanks for the extensive info. I'll take a look into it today.


Sorry I've been slow to respond to this, I'll try to make time today to look into it some more.


I just realized that we have a more basic problem. It is not related to accepts_nested_attributes_for. I am not sure it is a new issue or related to this one.

From the previous models:

Author.create(:name => "emre")
#<Author id: 1, name: "emre", slug: "emre">

Author.create(:name => "emre")
#<Author id: 2, name: "emre", slug: "emre--2">

last_author = Author.find(2)
#<Author id: 2, name: "emre", slug: "emre--2">

Everything is normal up to here. But when i save the first author:

first_author = Author.find(1)
#<Author id: 1, name: "emre", slug: "emre--3">
# [#<Author id: 1, name: "emre", slug: "emre--3">, #<Author id: 2, name: "emre", slug: "emre--2">]

Some new info:

Author.create(:name => "norman")
#<Author id: 3, name: "norman", slug: "norman">
# true

should_generate_new_friendly_id? returns true just after i create a record. Is it normal?

I override should_generate_new_friendly_id? for temporary solution.

def should_generate_new_friendly_id?

Sorry for commenting so much but i think i got one step closer to the problem's reason. It is about callback chain.

On Slugged module, set_slug method added to before_validation callbacks. In set_slug method should_generate_new_friendly_id? method is called and in should_generate_new_friendly_id? current_friendly_id method is called. But @current_friendly_id attribute is tried to set on a before_save callback.

So should_generate_new_friendly_id? method always returns true because when it is called current_friendly_id is always nil.


should_generate_new_friendly_id? should always return true when creating a new record (unless the slug is nil) so I don't think this is an issue. I'm looking into the app you sent me now, I suspect there's a bug with friendly_id and polymorphic models - will try to have a solution in place today. Thanks for your patience with my slow response.

@norman norman added a commit that referenced this issue Nov 24, 2011
@norman Fix unintended slug resequencing on update
Fixes issue raised in #185

Please try your app against FriendlyId master now, I've added a change to address the resequencing issue. You were right - the callback chain was definitely a factor in the bug. Thanks again for the report.


callback chain bug seems resolved but accepts_nested_attributes_for bug remains.
thanks for the patch.


Ok, so I've looked into this at length and it's not a simple problem to solve. I think the best course will be to generate the slug in a before_validation callback, and then generate the sequence in a before_save callback. Otherwise in cases like this, FriendlyId does two queries to check if a slug is being used before doing an insert, so it's impossible to detect collisions.

@norman norman added a commit that referenced this issue Dec 15, 2011
@norman Document some common issues with slugs.
This pertains to issues #180 and #185

For now I'm going to leave this issue documented but not fix it, as it would be too significant a change so close to a release, and there are some fairly simple workarounds. I've just added a commit that references this issue, and it can be reopened in the future.

@norman norman closed this Dec 15, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment