This is a very noob question, I am starting with Rails. I have a class User that has many Rates and each rates belongs to a user.
Rate Class
class Rate < ActiveRecord::Base
belongs_to :user
end
User Class
class User < ActiveRecord::Base
include Authenticable
has_many :rates
validates :username, uniqueness: true, allow_blank: true, allow_nil: true
Migration of Rates
class CreateRates < ActiveRecord::Migration
def change
create_table :rates do |t|
t.string :points
t.timestamps null: false
end
end
end
Migration of User
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: true, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.inet :current_sign_in_ip
t.inet :last_sign_in_ip
t.string :authentication_token, default: ""
## User attributes
t.string :username, default: ""
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
add_index :users, :authentication_token, unique: true
end
end
When I create the database and run rake db:migrate, all entity are migrated ok but the table rate has not user_id
You need to add user_id column to rates table
Hard to say without seeing the migration files themselves, but you can use the add_reference function in your migrations to add a reference to a table:
class AddUserIdToRate < ActiveRecord::Migration
def change
unless column_exists? :rates, :user_id
add_reference :rates, :user, index: true
end
end
end
If you get an error, post it here and we can hopefully provide more information.
Edit
There's nothing in your migrations involving the creation of a user_id column on your rates table. Adding a migration with the above code should add the user_id foreign key.
Related
I've applied uniqueness validation to "appeal_id" in model named "Campaigns". It asks me to add a unique index for uniqueness validation, I added campaign_id as a unique index. But it still shows the same error.
app/models/campaign.rb:9:3: C: Rails/UniqueValidationWithoutIndex: Uniqueness validation should have a unique index on the database column.
validates :appeal_id, uniqueness: { scope: :user_id }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
My schema for campaigns table looks like following:
create_table "campaigns", force: :cascade do |t|
t.string "title"
t.text "description"
t.bigint "appeal_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "campaign_id"
t.index ["appeal_id"], name: "index_campaigns_on_appeal_id"
t.index ["campaign_id"], name: "index_campaigns_on_campaign_id", unique: true
t.index ["user_id"], name: "index_campaigns_on_user_id"
end
"campaign.rb" file is as follows:
class Campaign < ApplicationRecord
has_many :donations, dependent: :destroy
belongs_to :appeal
belongs_to :user
validates :title, presence: true
validates :description, presence: true
validates :appeal_id, uniqueness: { scope: :user_id }
end
You're missing the compound index that you actually need to ensure that the combination of the two columns is unique.
Adding it is relatively simple:
class AddUniqueCompoundIndexToCampaigns < ActiveRecord::Migration[7.0]
def change
add_index [:appeal_id, :user_id], unique: true
end
end
I dropped my database and then edited my create_campaign migration and added this line of code
add_index :campaigns, [:appeal_id, :user_id], unique: true
in my migration. Then run the command
rails db:create db:migrate
which actually created my database again and resolved the issue of unique index.
class CreateCampaigns < ActiveRecord::Migration[7.0]
def change
create_table :campaigns do |t|
t.string :title
t.text :description
t.references :appeal, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :campaigns, [:appeal_id, :user_id], unique: true
end
end
I have a User model with uuid for id column.
Ahoy gem creates visits as expected but the user_id is wrong.
Any ideas?
ok. Got that. Ahoy gem doesn't work with user_id as UUID. It takes the first digits from uuid and stores that in user_id for Ahoy::Visit which could look like random value.
The solution is to change the user_id type to uuid.
This migration would do the trick:
class ChangeAhoyVisits < ActiveRecord::Migration[5.2]
def change
Ahoy::Visit.destroy_all
remove_column :ahoy_visits, :user_id, :bigint
add_column :ahoy_visits, :user_id, :uuid, foreign_key: true, null: true
add_index :ahoy_visits, :user_id
end
end
Probably need to add the same type: :uuid to the user_id column in the ahoy_events table as well. After a few rake db:rollback's I ended up modifying the original migration file that is created by rails generate ahoy:install to look like this before I ran the migration:
def change
create_table :ahoy_visits do |t|
t.string :visit_token
t.string :visitor_token
# the rest are recommended but optional
# simply remove any you don't want
# user
t.references :user, type: :uuid, foreign_key: true, index: true
# standard
t.string :ip
t.text :user_agent
t.text :referrer
t.string :referring_domain
t.text :landing_page
# technology
t.string :browser
t.string :os
t.string :device_type
# location
t.string :country
t.string :region
t.string :city
t.float :latitude
t.float :longitude
# utm parameters
t.string :utm_source
t.string :utm_medium
t.string :utm_term
t.string :utm_content
t.string :utm_campaign
# native apps
t.string :app_version
t.string :os_version
t.string :platform
t.datetime :started_at
end
add_index :ahoy_visits, :visit_token, unique: true
create_table :ahoy_events do |t|
t.references :visit
t.references :user, type: :uuid, foreign_key: true, index: true
t.string :name
t.jsonb :properties
t.datetime :time
end
add_index :ahoy_events, [:name, :time]
add_index :ahoy_events, :properties, using: :gin, opclass: :jsonb_path_ops
end
And after running this slightly modified migration rather than original everything seemed to populate properly on an 'ahoy.track' in the db.
In my Rails project with a Postgres database, I have a user and workspace model. They are associated by a many to many relationship (users_workspaces). If I open up my rails console and try to get all user workspaces with UserWorkspace.all, I get the following 'relation does not exist' error:
2.5.1 :001 > UserWorkspace.all
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: relation "user_workspaces" does not exist)
LINE 1: SELECT "user_workspaces".* FROM "user_workspaces" LIMIT $1
^
: SELECT "user_workspaces".* FROM "user_workspaces" LIMIT $1
2.5.1 :002 >
I don't understand why it's looking for user_workspaces (user being singular) rather than users_workspaces (both names plural). I'll looked through my codebase to see if this is in fact set somewhere as user_workspaces, but can't find it. I've also run rails db:drop db:create db:migrate, but still no luck. Here are related files, but I'm not sure where is issue is originating from.
user model
class User < ApplicationRecord
has_secure_password
has_and_belongs_to_many :workspaces
validates_presence_of :username, :email, :password, :subscription_plan
validates_uniqueness_of :username, :email
validates_length_of :username, :within => 3..40
validates_length_of :password, :within => 8..100
end
workspace model
class Workspace < ApplicationRecord
has_and_belongs_to_many :users
validates_presence_of :name
validates_presence_of :admin_id
end
user_workspace model
class UserWorkspace < ApplicationRecord
belongs_to :user
belongs_to :workspace
validates_presence_of :user, :workspace
end
schema.rb
ActiveRecord::Schema.define(version: 2018_07_28_040836) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: :cascade do |t|
t.string "username", null: false
t.string "email", null: false
t.string "first_name"
t.string "last_name"
t.string "password_digest"
t.integer "subscription_plan", default: 0, null: false
t.integer "current_workspace"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["username"], name: "index_users_on_username", unique: true
end
create_table "users_workspaces", id: false, force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "workspace_id", null: false
t.index ["user_id", "workspace_id"], name: "index_users_workspaces_on_user_id_and_workspace_id"
t.index ["workspace_id", "user_id"], name: "index_users_workspaces_on_workspace_id_and_user_id"
end
create_table "workspaces", force: :cascade do |t|
t.string "name", null: false
t.text "description"
t.integer "admin_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
users migrations
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :username, null: false, index: {unique: true}
t.string :email, null: false, unique: true
t.string :first_name
t.string :last_name
t.string :password_digest
t.integer :subscription_plan, null: false, default: 0
t.integer :current_workspace
t.timestamps
end
end
end
workspaces migration
class CreateWorkspaces < ActiveRecord::Migration[5.2]
def change
create_table :workspaces do |t|
t.string :name, null: false
t.text :description
t.integer :admin_id
t.timestamps
end
end
end
users_workspaces (join table) migration file
class CreateJoinTableUsersWorkspaces < ActiveRecord::Migration[5.2]
def change
create_join_table :users, :workspaces do |t|
t.index [:user_id, :workspace_id]
t.index [:workspace_id, :user_id]
end
end
end
Any and all help would be greatly appreciated. Thanks!
As mentioned in schema.rb table is created by the name users_workspaces and your class name is UserWorkspaces.
By default, rails try to infer the table name for a Model by its class name.
So, If classname is UserWorkspace then its corresponding table_name will be user_workspaces and not users_workspaces.
Now, You have two options either rename your model or somehow mention in your model that the table you want to use for this model.
Option-1
Rename Model
class UsersWorkspace < ApplicationRecord
belongs_to :user
belongs_to :workspace
validates_presence_of :user, :workspace
end
Option-2
Allow UserWorkspace model to point to users_workspaces table
class UserWorkspace < ApplicationRecord
self.table_name = 'users_workspaces'
belongs_to :user
belongs_to :workspace
validates_presence_of :user, :workspace
end
UPDATE
In addition to above in UserWorkspace/UsersWorkspace Model you don't need
validates_presence_of :user, :workspace
as since you are using rails 5.2, therefore, rails itself adds presence validation along with belongs_to association unless you have pass optional: true argument or you have declared it in the following way in application.rb
Rails.application.config.active_record.belongs_to_required_by_default = false
I'm getting a database ROLLBACK with this error in development when I try to update a Puzzle object's User object through the Rails console:
TypeError: can't cast ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array::Data
This only happens when I attempt to use update (or save after something like puzzle.user = some_user). Adding the initial owner commits to the database without issue.
Here are the models in the schema:
create_table "users", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "location_id"
end
create_table "puzzles", force: :cascade do |t|
t.string "name"
t.integer "pieces"
t.integer "missing_pieces"
t.string "previous_owners", array: true
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
And here are the puzzle.rb and user.rb files so far:
class User < ApplicationRecord
validates :username, presence: true
validates :email, presence: true#, uniqueness: true
# use bcrypt for password security
has_secure_password
has_many :puzzles
has_many :reviews
belongs_to :location
end
class Puzzle < ApplicationRecord
validates :name, uniqueness: true
validates :pieces, presence: true, numericality: { only_integer: true }
belongs_to :user
has_many :puzzle_tags
has_many :tags, through: :puzzle_tags
has_many :reviews
delegate :location, to: :user
end
Any idea what could be causing the issue?
***Please note: I'm a newbie and using PostgreSQL for the first time. I specifically chose Postgres as my development database instead of SQLite3 because it allows for array data types. Thanks!
You have previous_owners set up as a string array, but you are pushing integers into it. ActiveRecord is good at casting strings to integers and vice versa normally, but as of Rails 5.1.5, that functionality doesn't work in array fields.
Try using a migration to change the field to an integer array. You'll need to do:
$ rails g migration change_previous_owners_to_integer_array
Then edit the resulting migration file like this:
def change
remove_column :puzzles, :previous_owners, :string, array: true
add_column :puzzles, :previous_owners, :integer, array: true
end
I am getting this while i use Postgres.
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "retailers" does not exist
: ALTER TABLE "stations" ADD CONSTRAINT "fk_rails_57ee36b830"
FOREIGN KEY ("retailer_id")
REFERENCES "retailers" ("id")
/home/suyesh/Desktop/Petrohub_main/db/migrate/20160104152245_create_stations.rb:3:in `change'
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation "retailers" does not exist
: ALTER TABLE "stations" ADD CONSTRAINT "fk_rails_57ee36b830"
FOREIGN KEY ("retailer_id")
REFERENCES "retailers" ("id")
/home/suyesh/Desktop/Petrohub_main/db/migrate/20160104152245_create_stations.rb:3:in `change'
PG::UndefinedTable: ERROR: relation "retailers" does not exist
/home/suyesh/Desktop/Petrohub_main/db/migrate/20160104152245_create_stations.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Here are my stations and retailers model.
Retailer
class Retailer < User
has_many :stations
has_many :retailer_suppliers
has_many :suppliers , through: :retailer_suppliers, as: :connections
end
Stations
class Station < ActiveRecord::Base
belongs_to :retailer
has_many :tanks
end
Here is my Station Migration
class CreateStations < ActiveRecord::Migration
def change
create_table :stations do |t|
t.string :brand
t.string :business_name
t.string :tax_id
t.string :phone_number
t.string :contact_person
t.string :cell_number
t.string :address1
t.string :address2
t.string :city
t.string :state
t.string :zip
t.string :station_reg_number
t.references :retailer, index: true, foreign_key: true
t.timestamps null: false
end
end
end
I dont have retailer migration because its inheriting from the User. Here is my User migration
User
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
Add Type to User
class AddTypeToUsers < ActiveRecord::Migration
def change
add_column :users, :type, :string
end
end
Add extra attributes to user
class AddExtraToUsers < ActiveRecord::Migration
def change
add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :phone_number, :string
add_column :users, :cell_number, :string
add_column :users, :tax_id, :string
add_column :users, :business_name, :string
add_column :users, :address1, :string
add_column :users, :address2, :string
add_column :users, :city, :string
add_column :users, :state, :string
add_column :users, :zip_code, :string
add_column :users, :years_in_business, :string
end
end
And add account number to user
class AddAccountNumberToUsers < ActiveRecord::Migration
def change
add_column :users, :account_number, :string
add_index :users, :account_number
end
end
It works with no errors when i use Sqlite3 but i get errors in Production heroku using postgres. so i decided to use postgres in developemnt and i saw the above errors which i cannot understand. Thank you in advance
PG::UndefinedTable: ERROR: relation "retailers" does not exist
This error simply means that the retailers table is not present in your database when you try to reference this in another place. All you need is to make sure you create retailers table before you try to use/reference it in some some migration.
The error is coming from this line in your migration:
t.references :retailer, index: true, foreign_key: true
The foreign key option means that rails is trying to create a foreign key between retailer_id on the stations table and id on the non existant retailers table.
Although migrations are frequently created at the same time as a model, they're not really connected - the migration doesn't know that retailer is an STI model.
As far as I can tell you will need to remove the foreign key option from the call to references and add the foreign separately with add_foreign_key:
add_foreign_key :stations, :users, column: "retailer_id"
You probably didn't encounter this in development because earlier versions of sqlite3 didn't support foreign keys and current versions require that it be activated (see docs): unless activated it just ignores foreign key constraints (as long as they are syntactically correct)