Unique model field at databse level in Rails 3.1+ migration? - ruby-on-rails-3

Is there a way to specify a database level uniqueness constraint on a field in a Rails 3.1+ migration? I know ActiveRecord's validates_uniqueness_of would work, but I'm curious to know if this can be specified elsewhere.
For example, in order to specify that the 'login' field should be unique in a migration such as ...
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :login
t.timestamps
end
end
end
... I'd like to add an option like :unique => true.
There's nothing mentioned in the Documentation so I assume that's not a great place/way to do things, but does anyone know how this might be achieved (even if it's manually added to the resulting schema)? Or is validates_uniqueness_of the preferred way to go?

You can add unique index so:
def change
create_table :users do |t|
t.string :name
t.string :login
t.timestamps
end
add_index :users, :login, :unique => true
end

Related

Pull data from multiple tables in Rails

I am new in Ruby on Rails and I am trying to make a book registration website. Everything works fine except category section. When a user assign a category to his book, my database copies book_categories.id and put it in book.book_categories_id. The website also have a profile page, where you can view user's book(s). My problem is to display a category.name, I searched a lot of similar problems but I have not found the right answer.
Here is my book controller:
before_action :set_book, except: [:index, :new, :create]
before_action :authenticate_user!, except: [:show]
def show
#photos = #book.photos
end
def index
#books = current_user.books
end
def new
#book = current_user.books.build
end
def create
#book = current_user.books.build(books_params)
if #book.save
redirect_to listing_book_path(#book), notice: "Saved."
else
flash[:alert] = "Failed."
render :new
end
end
private
def set_book
#book = Book.find(params[:id])
end
def book_params
params.require(:book).permit(:book_categories_id, :book_name, :summary, :address, :price, :company_name)
end
As long as I understand, I have to allow my controller to have access to my category table but I do not know how. Also, all of my categories store in seed.rb.
This is my BookCategory.rb model:
class BookCategory < ActiveRecord::Base
has_many :books, :foreign_key => :book_categories_id
end
Book.rb model:
class Book < ApplicationRecord
belongs_to :user, :foreign_key => 'user_id'
has_many :photos, dependent: :delete_all
validates :book_name, presence: true
validates :book_categories_id, presence: true
def cover_photo
if self.photos.length > 0
self.photos[0].image.url
else
"default/image-default.jpg"
end
end
end
My schema.rb:
create_table "book_categories", force: :cascade do |t|
t.string "name"
t.string "subcategory"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "book", force: :cascade do |t|
t.string "book_name"
t.text "summary"
t.string "address"
t.decimal "price", precision: 8, scale: 2
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.float "latitude"
t.float "longitude"
t.string "company_name"
t.integer "book_categories_id"
t.index ["book_categories_id"], name: "index_books_on_book_categories_id"
end
Usually, when I type #book_categories.name, I get an error:
undefined method `name' for nil:NilClass
And at the very end, it says Parameters: {"id"=>"15"} whereas the category.id is different, and it passes book.id instead.
What I am doing wrong?
First fix the naming problem you have going. I don't know how the books table got called "book" instead of "books" in the schema, but you might have to fix that first.
Then category should be singular everywhere except the database table name. You need to make a migration to fix the foreign key and its index in the books table something like this:
class FixCategoryNaming < ActiveRecord::Migration
def change
remove_column :books, :book_categories_id
add_reference :books, :book_category, index: true, foreign_key: true
end
end
Then run rails db:migrate and check the schema looks ok
Then in the BookCategory class change the line to simply
has_many :books
You need to add this line to your Book class
belongs_to :book_category
and change the validation for book_category to be this
validates :book_category_id, presence: true
Then in the view for book index you have a #books variable. You can get the book name and category name for each book like this:
<% #books.each do |book| %>
<p><%= book.book_name %></p>
<p><%= book.book_categories.name %></p>
<% end %>
I think you need to setup as has_many through relationship. This is a good place to start http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Adding attribute to already existing model

I am trying to add user:references onto my already existing model. This is what I originally wrote:
rails g model Post title:string description:text
I do this to add the user:references by running rails generate migration add_user_to_posts user:references, I am receiving this error upon running rake db:migrate:
-- create_table(:users)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "users" already exists
I am reading the error and I understand I already have a User model, however, I want to add this attribute to the Post model, not the User model.
Db file:
Posts:
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
t.string :title
t.text :description
t.timestamps
end
end
end
Trying to add the user to posts:
class AddUserToPosts < ActiveRecord::Migration[5.0]
def change
add_reference :posts, :user, foreign_key: true
end
end
Users:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :uid
t.string :avatar_url
t.timestamps
end
add_index :users, :uid
end
end
However, rake db:migrate gives me the error above.

using activeuuid gem for existing database in rails

I need to implement activeuuid gem to have UUIDs instead of default Rails ids. we can implement it for creating new migration as:
class CreateStudents < ActiveRecord::Migration
def change
create_table :students, :id => false do |t|
t.uuid :id, :primary_key => true
t.string :name
t.string :email
t.timestamps
end
end
end
And in model we include ActiveUUID::UUID as:
class Student < ActiveRecord::Base
attr_accessible :email, :name
include ActiveUUID::UUID
end
Now I already have a database so how can I implement the activeuuid gem to have UUIDs instead of default Rails ids for existing DB?
Need to make changes in all migrations or what?
Need help in this regard. thanks
The UUID is stored as a binary field w/ 16 positions as I found here: https://github.com/jashmenn/activeuuid/blob/master/lib/activeuuid/patches.rb#L62
It worked for me (existing table without records):
def change
reversible do |dir|
change_table :payments do |t|
dir.up { t.change :id, :binary, limit: 16, :primary_key => true }
dir.down { t.change :id, :integer }
end
end
end
Don't forget to add those lines to your model as well:
include ActiveUUID::UUID
natural_key :at_least_one_field_here
More info in the github repo: https://github.com/jashmenn/activeuuid/

Ruby on Rails Has_Many :Through Association

I'm having some problems with ruby on rails, specifically setting up a many-to-many connection with deal and event through deal_event. I've checked out several similar stackoverflow questions and even http://guides.rubyonrails.org/ but I'm still not getting something..
Here are my models:
deal.rb
class Deal < ActiveRecord::Base
has_many :deal_events
has_many :events, :through => "deal_events"
attr_accessible :approved, :available, :cents_amount, :dollar_amount, :participants, :type
end
event.rb
class Event < ActiveRecord::Base
has_many :deal_events
has_many :deals, :through => "deal_events"
attr_accessible :day, :image, :description, :location, :title, :venue, :remove_image
end
deal_event.rb
class DealEvent < ActiveRecord::Base
belongs_to :deal
belongs_to :event
end
And here are my migration files:
20130102150011_create_events.rb
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :title, :null => false
t.string :venue
t.string :location
t.text :description
t.date :day
t.timestamps
end
end
end
20130112182824_create_deals.rb
class CreateDeals < ActiveRecord::Migration
def change
create_table :deals do |t|
t.integer :dollar_amount
t.integer :cents_amount
t.integer :participants
t.string :type, :default => "Deal"
t.integer :available
t.string :approved
t.timestamps
end
end
end
20130114222309_create_deal_events.rb
class CreateDealEvents < ActiveRecord::Migration
def change
create_table :deal_events do |t|
t.integer :deal_id, :null => false
t.integer :event_id, :null => false
t.timestamps
end
end
end
After I seed my database with one deal and one event, I go into the console and type in
deal = Deal.first # ok
event = Event.first # ok
DealEvent.create(:deal => deal, :event => event) # Error: ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: deal, event
deal.events # Error: ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association "deal_events" in model Deal
Any idea on what I'm doing wrong for these two errors to be popping up? Thanks.
You'll need this line in your DealEvent model:
attr_accessible :deal, :event
Although if it's just a relationship table (which it looks like) then you don't create the relationship that way. Use nested forms and the like.

how to generate a unique debitnote number automatically

in my rails3 app i have a debitnote controller ,model and views created by scaffold.
i show you the migration:
class CreateDebitnotes < ActiveRecord::Migration
def self.up
create_table :debitnotes do |t|
t.string :debit_note_number
t.date :date
t.decimal :amount, :precision =>18, :scale => 2
t.string :debit_account_of
t.string :debit_for
t.text :description
t.timestamps
end
end
def self.down
drop_table :debitnotes
end
end
in my app i want to automatically generate a unique debitnote number when user open new form to create a deb
You may use UUID generator github repo