AcceptsNestedAttributesForPublicId

Gem Version CI Status RubyGems Downloads

A patch for Rails to support using a public ID column instead of ID for use with accepts_nested_attributes_for

Supports Rails 5, 6, 7+

Why:

  • By default ActiveRecord and accepts_nested_attributes_for does not respect to_param or provide any ability to utilize a public ID column. This results in your DB primary keys being exposed in your forms.
  • This was extracted from a PR to Rails core until this functionality is otherwise achievable in Rails core proper.

Installation

gem 'accepts_nested_attributes_for_public_id'

Usage

You now have access to the following options:

Option A: Define a accepts_nested_attributes_for_public_id_column method on your class

class Post < ApplicationRecord
  has_many :comments
  accepts_nested_attributes_for :comments
end

class Comment < ApplicationRecord
  belongs_to :post

  def self.accepts_nested_attributes_for_public_id_column
    :my_public_id_db_column
  end
end

Option B: Use the :public_id_column option on accepts_nested_attributes_for

class Post < ApplicationRecord
  has_many :comments
  accepts_nested_attributes_for :comments, public_id_column: :my_public_id_db_column
end

class Comment < ApplicationRecord
  belongs_to :post
end

How is this safe

The code for Nested Attributes in Rails core has not changed since around Rails 4 (Rails 7.0 is the current release at the time of writing this)

Because this patch requires changes in the very middle of some larger sized methods we are unable to use super in the patches. This can make it fragile if new changes were introduced to Rails core.

We have taken steps to ensure that no issues are caused by any future Rails changes by adding runtime contracts that ensure the original method source matches our saved contract of the current sources of these methods. If a new Rails version were to change the original method source then you would receive a runtime error stating that we are unable to apply the patch until the gem has been made compatible with any changed code.

Testing

RAILS_ENV=test bundle exec rake db:create
RAILS_ENV=test bundle exec rake db:migrate
bundle exec rspec

We can locally test different versions of Rails using ENV['RAILS_VERSION'] and different database gems using ENV['DB_GEM']

export RAILS_VERSION=7.0
export DB_GEM=sqlite3
bundle install
bundle exec rspec

Credits

Created & Maintained by Weston Ganger - @westonganger