create_table :categories_posts, :id => false do |t|
  t.column :category_id, :integer, :null => false
  t.column :post_id, :integer, :null => false

I've got a join table (as above) with posts that make reference to a corresponding groups table along with a posts table. I needed to enforce a distinctive constraint on the composite key category_id, publish_id within the groups_posts join table. But Rails doesn't support this (In my opinion).

To prevent the opportunity of duplicate rows during my data getting exactly the same mixture of category_id and publish_id, what is the best workaround for the lack of an amalgamated type in Rails?

My presumptions listed here are:

  1. The default auto-number column (id:integer) would do nothing at all to safeguard my data in cases like this.
  2. ActiveScaffold may give a solution but I am unsure if it's overkill to incorporate it during my project only for this single feature, particularly if there's a more elegant answer.

Give a unique index which includes both posts. Which will stop you from placing an archive that consists of a replica category_id/publish_id pair.

add_index :categories_posts, [ :category_id, :post_id ], :unique => true, :name => 'by_category_and_post'

I believe you'll find simpler to validate originality of among the fields using the other like a scope:

In The API:


Validates whether the need for the required characteristics are unique over the system. Helpful for ensuring just one user could be named "davidhh".

  class Person < ActiveRecord::Base
    validates_uniqueness_of :user_name, :scope => :account_id

Additionally, it may validate whether the need for the required characteristics are unique according to multiple scope parameters. For instance, ensuring an instructor are only able to be around the schedule once per semester for the class.

  class TeacherSchedule < ActiveRecord::Base
    validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id]

Once the record is produced, a cheque is carried out to make certain that no record is available within the database using the given value for that specified attribute (that maps to some column). Once the record is up-to-date, exactly the same check is created but neglecting the record itself.

Configuration options:

* message - Specifies a custom error message (default is: "has already been taken")
* scope - One or more columns by which to limit the scope of the uniquness constraint.
* case_sensitive - Looks for an exact match. Ignored by non-text columns (true by default).
* allow_nil - If set to true, skips this validation if the attribute is null (default is: false)
* if - Specifies a method, proc or string to call to determine if the validation should occur (e.g. :if => :allow_validation, or :if => { |user| user.signup_step > 2 }). The method, proc or string should return or evaluate to a true or false value.

I implement each of the next after i have this problem in rails:

1) You ought to have a distinctive composite index declared in the database level to make sure that the dbms will not let a replica record get produced.

2) To supply softer error msgs than simply the above mentioned, give a validation towards the Rails model:

validates_each :category_id, :on => :create do |record, attr, value|
  c = value; p = record.post_id
  if c && p && # If no values, then that problem 
               # will be caught by another validator
    CategoryPost.find_by_category_id_and_post_id(c, p)
    record.errors.add :base, 'This post already has this category'

An answer is usually to add both index and validation within the model.

So within the migration you've: add_index :groups_posts, [:category_id, :publish_id], :unique => true

As well as in the model: validates_originality_of :category_id, :scope => [:category_id, :publish_id] validates_originality_of :publish_id, :scope => [:category_id, :publish_id]