How could duplicate rows be created with the schema - ruby-on-rails-3

In Rail, I have this schema (for a join table between car and user habtm)
create_table "cars_users", :id => false, :force => true do |t|
t.integer "user_id"
t.integer "car_id"
end
add_index "cars_users", ["car_id", "user_id"], :name => "index_cars_users_on_car_id_and_user_id"
add_index "cars_users", ["user_id", "car_id"], :name => "index_cars_users_on_user_id_and_car_id"
but due to some bug, I have duplicate rows in this table.
shouldn't the index handle that?

Try:
add_index :cars_users, [ :user_id, :car_id ], :unique => true, :name => 'by_user_and_car'
it will raise an exception but you can add your own validation
class User < ActiveRecord::Base
has_and_belongs_to_many :cars, :before_add => :validates_car
def validates_car(car)
errors.add(:car, "already created" ) if self.cars.include? car
end
end

Related

How to call references to other tables in a model rails

I have a model called cause.rb which has a scope called pesquisa that I want to query in the table causes, fields that are references to other tables. I want to call the table places which have a field called city from the model cause.
Causes table:
class CreateCauses < ActiveRecord::Migration
def change
create_table :causes do |t|
t.string :title, null: false
t.text :description, null: false
t.boolean :anonymous, default: false
t.integer :count_likes, default: 0
t.integer :count_dislikes, default: 0
t.integer :count_visits, default: 0
t.references :user
t.references :category
t.timestamps
end
add_index :causes, :user_id
add_index :causes, :category_id
end
end
class AddPlaceIdToCauses < ActiveRecord::Migration
def change
add_column :causes, :place_id, :integer
end
end
Places table:
class CreatePlaces < ActiveRecord::Migration
def change
create_table :places do |t|
t.string :description
t.decimal :latitude
t.decimal :longitude
t.references :city
t.timestamps
end
add_index :places, :city_id
end
end
Here is the scope:
scope :pesquisa, ->(pesquisa) { where("cause.place.city like :p or category_id like :p ", p: "%#{pesquisa}%") }
default_scope :order => "id desc"
How do I resolve this problem? I try this above cause.place.city to call the city in the table places but nothing happens.

Rails PG::Error Presentation and Handling of Unique Constraint

I am developing on Rails 4 with postgres and devise. I have the following User model:
# user model
class User < ActiveRecord::Base
extend FriendlyId
friendly_id :username, :use => :slugged
rolify
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable
validates :username, :presence => true, :uniqueness => {:case_sensitive => false}, :length => { :minimum => 3 },
:format => { :with => /\A[A-Z0-9a-z\w\b\ \-\_\'\!&##\.]+\z/i,
:message => "may contain only alphanumeric characters and common special characters." }
validates :email, :uniqueness => {:case_sensitive => false}, :presence => true,
:format => { :with => Devise.email_regexp, :message => "isn't valid"}
validates :password, length: { in: 6..128 }, on: :create
validates :password, length: { in: 6..128 }, on: :update, allow_blank: true
validates :slug, :presence => true
end
# in schema
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "username"
t.string "slug"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["slug"], name: "index_users_on_slug", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true
The fields email and username are unique indices of the users table. My user registration view was created from devise. I create a test account, for instance, with username "test", email "test#example.com", password "123456". I sign out and try to sign up with the same information. I am expecting that the :uniqueness validations to trigger and be rendered on a list of errors alongside the signup form, but instead I get a full-page error with:
ERROR: duplicate key value violates unique constraint "index_users_on_email"
DETAIL: Key (email)=(test#example.com) already exists.
How can I allow this error to bubble up to Rails and be shown as friendly single-line error like "Email is already registered with an account" alongside the sign up form instead of being caught with a big Rails error page?
I've identified the problem. The plugin friendly_id turned out not so friendly. It breaks uniqueness validation and results in 500 internal server errors. I have removed it from my application. Consider using something like ActsAsUrl in the Stringex library. I have removed
extend FriendlyId
friendly_id :username_copy, :use => :slugged
and am now using
acts_as_url :username, :sync_url => true, :url_attribute => :slug
to generate friendly urls.

Why is the user_id not automatically added upon creation of a comment?

I have a field that creates a comment (named pcomment). I am trying to get it to automatically add the user_id to the pcomment in the pcomment table like it adds the purchase_id automatically. I am not sure why the purchase_id is being recorded in the database but the user_id remains blank for each pcomment. Here is the form for the pcomment.
<%= form_for([purchase, purchase.pcomments.build], :html => { :id => "blah_form" }) do |f| %>
<div class="field">
<h4>What deal are you offering?</h4>
<%= f.text_field :body %>
</div>
<% end %>
It may be that I have to add some hidden_field, but I don't think so. I am using http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#cha-user_microposts as resource and in that the microposts dont have any hidden_field. Instead, the user_id is indexed and it automatically is created upon the creation of a micropost (based on who is signed in at the time). This part is working for me too, adding to my rational that indexing user_id on the pcomments table is enough to automatically generate it. Here is my schema.rb file so that you can see the current state of my database.
ActiveRecord::Schema.define(:version => 20121011085147) do
create_table "pcomments", :force => true do |t|
t.string "body"
t.integer "purchase_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "pcomments", ["purchase_id"], :name => "index_pcomments_on_purchase_id"
add_index "pcomments", ["user_id"], :name => "index_pcomments_on_user_id"
create_table "purchases", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "purchases", ["user_id", "created_at"], :name => "index_purchases_on_user_id_and_created_at"
create_table "sales", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "sales", ["user_id", "created_at"], :name => "index_sales_on_user_id_and_created_at"
create_table "scomments", :force => true do |t|
t.string "body"
t.integer "sale_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "scomments", ["sale_id"], :name => "index_scomments_on_sale_id"
add_index "scomments", ["user_id"], :name => "index_scomments_on_user_id"
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["remember_token"], :name => "index_users_on_remember_token"
end
and the reason I know its not working is that I check in the database and the pcomment is successfully created with all columns filled in including purchase_id but the user_id is still blank. also, the user has_many pcomments and has_many purchases. The purchase has_many pcomments and belongs_to user. The pcomment belongs_to user and belong_to purchase.
also, here is the pcomments_controller.rb
class PcommentsController < ApplicationController
before_filter :signed_in_user
def create
#purchase = Purchase.find(params[:purchase_id])
#pcomment = #purchase.pcomments.build(params[:pcomment], :user_id => #purchase.user_id)
#pcomment.purchase = #purchase
if #pcomment.save
flash[:success] = "Offer submited!"
redirect_to :back
else
render 'shared/_pcomment_form'
end
end
def new
#pcomment=purchase.pcomments.new
end
end
def new
#pcomment=purchase.pcomments.new(:user_id => purchase.user_id)
end
end
purchase.pcomments.build builds empty Pcomment object just with purchase_id filled from purchase. To assign also user_id pass the hash with attribute:
purchase.pcomments.build(:user_id => purchase.user_id)

Two associations from the same model possible?

I have a model Country (which is the same as 'Team') and a model Match and I am trying to build a scenario where I have a Match record with both home & away teams.
The models
class Country < ActiveRecord::Base
has_many :home_matches, :foreign_key => 'home', :class_name => "Match"
has_many :away_matches, :foreign_key => 'away', :class_name => "Match"
end
class Match < ActiveRecord::Base
belongs_to :home, :class_name => "Country", :foreign_key => "home"
belongs_to :away, :class_name => "Country", :foreign_key => "away"
end
The schemas
create_table "countries", :force => true do |t|
t.string "name"
t.text "bio"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "matches", :force => true do |t|
t.datetime "matchdate"
t.integer "home"
t.integer "away"
t.datetime "created_at"
t.datetime "updated_at"
end
Problem
This works well if I just want:
> canada.away_matches
> japan.home_matches
But how do I get all matches that a country is playing?
Update:
I found the answer in another reply.
ActiveRecord has two association
I have updated my Country model with the following code:
def matches
Match.where("home = ? OR away = ?", self, self)
end
Now I can query:
> canada.home_matches
> canada.away_matches
> canada.matches
And get the desired result.
You are setting up the associations in a wrong way.
Go through this
Single_Table_Inheritance wiki, and
single-table-inheritance-and-where-to-use-it-in-rails

Ruby on Rails model associations nubie question

dear developers I have some problems with Rails models
Here is my sql tables
create_table "areas", :primary_key => "ndc", :force => true do |t|
t.string "townname", :limit => 256, :null => false
end
create_table "books", :primary_key => "ndc", :force => true do |t|
t.integer "booked", :null => false
t.integer "free", :null => false
end
class Book < ActiveRecord::Base
self.primary_key = "ndc"
has_one :area, :foreign_key => 'ndc'
end
class Area < ActiveRecord::Base
self.primary_key = "ndc"
belongs_to :book , :foreign_key => 'ndc'
end
in controller I have such code
#books = Book.paginate :page => params[:page] || 1, :per_page => 10
#books.each do |booking|
p booking.area
p booking
end
In production mode doesn't work, booking.area is nil object. what it can be ?
Area becames nil if config.cache_classes = true
so booking.area generates such queries
if cashe_classes = true
SELECT areas.* FROM areas WHERE (areas.ndc = NULL) LIMIT 1
but without cashing classes
SELECT areas.* FROM areas WHERE (areas.ndc = 30) LIMIT 1
FIXED by removing belongs_to :book , :foreign_key => 'ndc' from area class.
Your areas table needs a book_id integer field to match against the books table's primary key.