{"id":15064656,"url":"https://github.com/brightcommerce/attr_sequence","last_synced_at":"2025-04-10T12:41:03.742Z","repository":{"id":56842643,"uuid":"162933227","full_name":"brightcommerce/attr_sequence","owner":"brightcommerce","description":"ActiveRecord concern that generates scoped sequential numbers for models.","archived":false,"fork":false,"pushed_at":"2018-12-24T01:46:22.000Z","size":9,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T11:21:32.176Z","etag":null,"topics":["activerecord","concern","macro","ruby-on-rails","sequencer"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brightcommerce.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"MIT-LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-24T00:21:54.000Z","updated_at":"2020-02-29T00:27:34.000Z","dependencies_parsed_at":"2022-09-01T06:31:46.284Z","dependency_job_id":null,"html_url":"https://github.com/brightcommerce/attr_sequence","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_sequence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_sequence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_sequence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brightcommerce%2Fattr_sequence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brightcommerce","download_url":"https://codeload.github.com/brightcommerce/attr_sequence/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247744333,"owners_count":20988783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","concern","macro","ruby-on-rails","sequencer"],"created_at":"2024-09-25T00:23:40.903Z","updated_at":"2025-04-10T12:41:03.722Z","avatar_url":"https://github.com/brightcommerce.png","language":"Ruby","readme":"# AttrSequence\n\nAttrSequence is an ActiveRecord concern that generates scoped sequential numbers for models. This gem provides an `attr_sequence` macro that automatically assigns a unique, sequential number to each record. The sequential number is not a replacement for the database primary key, but rather adds another way to retrieve the object without exposing the primary key.\n\nAttrSequence has been extracted from the Brightcommerce platform and is now used in multiple other software projects.\n\n## Installation\n\nTo install add the line to your `Gemfile`:\n\n``` ruby\ngem 'attr_sequence'\n```\n\nAnd run `bundle install`.\n\nThe following configuration defaults are used by AttrSequence:\n\n``` ruby\nAttrSequence.configure do |config|\n  config.column = :number\n  config.start_at = 1\nend\n```\n\nYou can override them by generating an initializer using the following command:\n\n``` bash\nrails generate attr_sequence:initializer\n```\n\nThis will generate an initializer file in your project's `config/initializers` called `attr_sequence.rb` directory.\n\n## Usage\n\nIt's generally a bad practice to expose your primary keys to the world in your URLs. However, it is often appropriate to number objects in sequence (in the context of a parent object).\n\nFor example, given a Question model that has many Answers, it makes sense to number answers sequentially for each individual question. You can achieve this with AttrSequence:\n\n``` ruby\nclass Question \u003c ActiveRecord::Base\n  has_many :answers\nend\n\nclass Answer \u003c ActiveRecord::Base\n  include AttrSequence\n  belongs_to :question\n  attr_sequence scope: :question_id\nend\n```\n\nTo autoload AttrSequence for all models, add the following to an initializer:\n\n``` ruby\nrequire 'attr_sequence/active_record'\n```\n\nYou then don't need to `include AttrSequence` in any model.\n\nTo add a sequential number to a model, first add an integer column called `:number` to the model (or you many name the column anything you like and override the default). For example:\n\n``` bash\nrails generate migration add_number_to_answers number:integer\nrake db:migrate\n```\n\nThen, include the concern module and call the `attr_sequence` macro in your model class:\n\n``` ruby\nclass Answer \u003c ActiveRecord::Base\n  include AttrSequence\n  belongs_to :question\n  attr_sequence scope: :question_id\nend\n```\n\nThe scope option can be any attribute, but will typically be the foreign key of an associated parent object. You can even scope by multiple columns for polymorphic relationships:\n\n``` ruby\nclass Answer \u003c ActiveRecord::Base\n  include AttrSequence\n  belongs_to :questionable, polymorphic: true\n  attr_sequence scope: [:questionable_id, :questionable_type]\nend\n```\n\nMultiple sequences can be defined by using the macro multiple times:\n\n``` ruby\nclass Answer \u003c ActiveRecord::Base\n  include AttrSequence\n  belongs_to :account\n  belongs_to :question\n\n  attr_sequence column: :question_answer_number, scope: :question_id\n  attr_sequence column: :account_answer_number, scope: :account_id\nend\n```\n\n## Schema and data integrity\n\n*This gem is only concurrent-safe for PostgreSQL databases.* For other database systems, unexpected behavior may occur if you attempt to create records concurrently.\n\nYou can mitigate this somewhat by applying a unique index to your sequential number column (or a multicolumn unique index on sequential number and scope columns, if you are using scopes). This will ensure that you can never have duplicate sequential numbers within a scope, causing concurrent updates to instead raise a uniqueness error at the database-level.\n\nIt is also a good idea to apply a not-null constraint to your sequential number column as well if you never intend to skip it.\n\nHere is an example migration for an `Answer` model that has a `:number` scoped to a `Question`:\n\n``` ruby\n# app/db/migrations/20180101000000_create_answers.rb\nclass CreateAnswers \u003c ActiveRecord::Migration\n  def change\n    create_table :answers do |table|\n      table.references :question\n      table.column :number, :integer, null: false\n      table.index [:number, :question_id], unique: true\n    end\n  end\nend\n```\n\n## Configuration\n\n### Overriding the default sequential ID column\n\nBy default, AttrSequence uses the `number` column and assumes it already exists. If you wish to store the sequential number in different integer column, simply specify the column name with the `:column` option:\n\n``` ruby\nattr_sequence scope: :question_id, column: :my_sequential_id\n```\n\n### Starting the sequence at a specific number\n\nBy default, AttrSequence begins sequences with 1. To start at a different integer, simply set the `start_at` option:\n\n``` ruby\nattr_sequence start_at: 1000\n```\n\nYou may also pass a lambda to the `start_at` option:\n\n``` ruby\nattr_sequence start_at: lambda { |r| r.computed_start_value }\n```\n\n### Indexing the sequential number column\n\nFor optimal performance, it's a good idea to index the sequential number column on sequenced models.\n\n### Skipping sequential ID generation\n\nIf you'd like to skip generating a sequential number under certain conditions, you may pass a lambda to the `skip` option:\n\n``` ruby\nattr_sequence skip: lambda { |r| r.score == 0 }\n```\n\n## Example\n\nSuppose you have a question model that has many answers. This example demonstrates how to use AttrSequence to enable access to the nested answer resource via its sequential number.\n\n``` ruby\n# app/models/question.rb\nclass Question \u003c ActiveRecord::Base\n  has_many :answers\nend\n\n# app/models/answer.rb\nclass Answer \u003c ActiveRecord::Base\n  include AttrSequence\n  belongs_to :question\n  attr_sequence scope: :question_id\n\n  # Automatically use the sequential number in URLs\n  def to_param\n    self.number.to_s\n  end\nend\n\n# config/routes.rb\nresources :questions do\n  resources :answers\nend\n\n# app/controllers/answers_controller.rb\nclass AnswersController \u003c ApplicationController\n  def show\n    @question = Question.find(params[:question_id])\n    @answer = @question.answers.find_by(number: params[:id])\n  end\nend\n```\n\nNow, answers are accessible via their sequential numbers:\n\n```\nhttp://example.com/questions/5/answers/1  # Good\n```\n\ninstead of by their primary keys:\n\n```\nhttp://example.com/questions/5/answer/32454  # Bad\n```\n\n## Dependencies\n\nAttrSequence gem has the following runtime dependencies:\n- activerecord \u003e= 5.1.4\n- activesupport \u003e= 5.1.4\n\n## Compatibility\n\nTested with MRI 2.4.2 against Rails 5.2.2.\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## Credit\n\nThis gem was written and is maintained by [Jurgen Jocubeit](https://github.com/JurgenJocubeit), CEO and President Brightcommerce, Inc.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n## Copyright\n\nCopyright 2018 Brightcommerce, Inc.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrightcommerce%2Fattr_sequence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrightcommerce%2Fattr_sequence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrightcommerce%2Fattr_sequence/lists"}