This is a rails project using ActiveRecord with Postgres.
Hi I'm working with two CSVs. One is a record of all registered voters in the state. When I created this table I didn't use a generated unique id as an indexed column, but instead used the already assigned state state_voter_id. Schema for Voter table:
create_table "voters", id: false, force: :cascade do |t|
t.string "state_voter_id", null: false
t.string "county_voter_id"
t.string "first_name"
t.string "middle_name"
t.string "last_name"
t.string "suffix"
t.string "birthdate"
t.string "gender"
t.string "add_st_num"
t.string "add_st_name"
t.string "add_st_type"
t.string "add_unit_type"
t.string "add_pre_direction"
t.string "add_post_direction"
t.string "add_unit_num"
t.string "city"
t.string "state"
t.string "zip"
t.string "county"
t.string "precinct"
t.string "leg_dist"
t.string "cong_dist"
t.string "reg_date"
t.string "last_vote"
t.string "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["city"], name: "index_voters_on_city"
t.index ["first_name"], name: "index_voters_on_first_name"
t.index ["last_name"], name: "index_voters_on_last_name"
t.index ["state_voter_id"], name: "index_voters_on_state_voter_id", unique: true
t.index ["zip"], name: "index_voters_on_zip"
end
I know want to add in a new table/model of vote records containing the state_voter_id as the reference to the Voter table
This is the migration I tried:
def change
create_table :votes do |t|
t.references :voter, column: :state_voter_id
t.string :county
t.string :date
t.timestamps
end
When I ran the migration It migrated, but when I tried to start seeding voter records I got the following error: ActiveRecord::UnknownPrimaryKey: Unknown primary key for table voters in model Voter. I also noted that the table was set up to take a bigint.
How do I set it up so that I am properly referencing the Voter on state_voter_id, which is an alphanumeric string?
Something along the lines of:
class AddPrimaryKeyToVoters < ActiveRecord::Migration
def change
change_column :voters, :state_voter_id, :primary_key
end
end
In your voters model add
self.primary_key = "state_voter_id"
The problem isn't with your migration, it's with your Model. You need this
class Voter < ApplicationRecord
self.primary_key = 'state_voter_id'
...
end
Note that's assuming Rails 5 with the new ApplicationRecord class. If you're using rails 4 then just inherit from ActiveRecord::Base as usual.
Related
I have two models: User and Listing.
I am trying to set up a one-to-many relationship between them via existing db columns.
class User < ApplicationRecord
has_many :listings
class Listing < ApplicationRecord
belongs_to :user, foreign_key: "user_id"
This is my migration:
class AddFkToListing < ActiveRecord::Migration[5.1]
def change
add_foreign_key :listings, :users, column: :user_id, primary_key: :user_id
end
end
But it created the foreign key in table users on column id.
Any idea how to do this properly?
Here is the DB schema:
create_table "listings", force: :cascade do |t|
t.integer "listing_id"
t.string "state"
t.integer "user_id"
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["listing_id"], name: "index_listings_on_listing_id", unique: true
end
create_table "users", force: :cascade 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_digest"
t.boolean "admin", default: false
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.datetime "reset_sent_at"
t.string "request_token"
t.string "request_secret"
t.string "oauth_verifier"
t.string "oauth_token"
t.string "login_name"
t.integer "user_id"
t.index ["email"], name: "index_users_on_email", unique: true
end
Thank you so much!
Since you have a conventional foreign key field name (user_id in listings table), I believe this should work just fine for you:
class AddFkToListing < ActiveRecord::Migration[5.1]
def change
add_foreign_key :listings, :users
end
end
The syntax of add_foreign_key is:
first argument (:listings) - table which should contain foreign key
second argument (:users) - table which should be used for constraint
column: :user_id - specifies to which field of the listings table constraint should be applied
primary_key: - specifies the field of the users table to build a constraint
(see https://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_foreign_key)
The primary_key: :user_id part in your example actually refers (tries to) to non-existing user_id field in users table.
I'm new to Rails (using 5.1) and I'm having trouble setting up my ActiveRecord associations.
Organizers can sign up and then create a club. An organizer belongs to one club (I guess could potentially have multiple but for now it's fine to expect just one). Clubs can have many organizers.
Clubs will always be created after the Organizer has been created so the foreign key on clubs is nil initially.
Here's the error I'm getting when trying to create an organizer without having any clubs already created:
ActiveRecord::InvalidForeignKey: ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: insert or update on table "organizers" violates foreign key constraint "fk_rails_bc04936880"
DETAIL: Key (club_id)=(0) is not present in table "club".
Organizer:
class Organizer < ApplicationRecord
belongs_to :club, optional: true
#also put config.active_record.belongs_to_required_by_default = false in application.rb
end
Club:
class Club < ApplicationRecord
has_many: organizers
end
Schema:
create_table "clubs", force: :cascade do |t|
t.string "full_name"
t.string "urn"
t.string "short_name"
t.string "address1"
t.string "address2"
t.string "city"
t.string "state"
t.string "zip"
t.string "website"
t.string "phone"
end
create_table "organizers", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "superuser", default: false
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.datetime "reset_sent_at"
t.bigint "club_id"
t.index ["club_id"], name: "index_organizers_on_club_id"
t.index ["email"], name: "index_organizers_on_email", unique: true
end
add_foreign_key "organizers", "clubs"
Thanks in advance for the help!
For some reason your code tries to set 0 value to club_id.
I would suggest forcing nil in this attribute and observe if error still occurs:
Organizer.create!(
#...
club_id = nil
)
I am making a Band application where a Venue has many Events and Bands through Events.
I realized that in my form for creating an event can only hold one band_id
but I want to have many bands because it only makes sense to do so.
This is my Schema
ActiveRecord::Schema.define(version: 20170817180728) do
create_table "bands", force: :cascade do |t|
t.string "name"
t.string "genre"
t.string "image"
t.boolean "explicit_lyrics"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "events", force: :cascade do |t|
t.string "name"
t.text "date"
t.boolean "alcohol_served"
t.string "image"
t.integer "venue_id"
t.integer "band_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "venues", force: :cascade do |t|
t.string "name"
t.string "city"
t.string "state"
t.boolean "family_friendly"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
These are my models
class Venue < ApplicationRecord
has_many :events
has_many :bands, through: :events
end
class Event < ApplicationRecord
belongs_to :venue
belongs_to :band
end
class Band < ApplicationRecord
has_many :events
end
I am fairly new to rails this is a practice web app. I want to be able to be able to show multiple band_ids to my event.
Would I just keep repeating t.band_id in my form??
You'll want to specify a foreign key relationship in your migration that reflects the Active Record associations you've set up in your models using belongs_to instead of a data type. This way, you'll get a references from one table to another, or in your case, from one table to two others, which is how one table with two one-to-many relationships is set up.
class CreateEvents < ActiveRecord::Migration
def change
create_table :venues do |t|
t.string :name
t.string :city
t.string :state
t.boolean :family_friendly
t.string :image
t.timestamps
end
create_table :bands do |t|
t.string :name
t.string :genre
t.string :image
t.boolean :explicit_lyrics
t.timestamps
end
create_table :events do |t|
t.belongs_to :venue, index: true # Look here!
t.belongs_to :band, index: true # and here!
t.string :name
t.text :date
t.boolean :alcohol_served
t.string :image
t.timestamps
end
end
end
I have a problem, I want to create an hashtags system, but when I run my code, and when I want to create a travel that contain hashtags I have this error :
ActiveRecord::StatementInvalid in TravelsController#create
Could not find table 'tags_travels'
Here is my travel.rb
class Travel < ApplicationRecord
has_many :posts
belongs_to :user
has_and_belongs_to_many :tags
#after / before create
after_create do
travel = Travel.find_by(id: self.id)
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
before_update do
travel = Travel.find_by(id: self.id)
travel.tags.clear
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
end
my tag.rb
class Tag < ApplicationRecord
has_and_belongs_to_many :travels
end
the schema.rb file (just table concerned) :
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.string "text"
t.string "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
create_table "travels", force: :cascade do |t|
t.string "name"
t.string "trip_type"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "hashtags"
end
create_table "travels_tags", id: false, force: :cascade do |t|
t.integer "travel_id"
t.integer "tag_id"
t.index ["tag_id"], name: "index_travels_tags_on_tag_id"
t.index
["travel_id"], name: "index_travels_tags_on_travel_id"
end
Someone has a solution ? Thank !
Rails looks for join tables in a specific syntax. Its trying to find tags_travles but uouve created it with travels_tags.
Change your model associations to specify the join table.
has_and_belongs_to_many :travels, :join_table => :travels_tags
And
has_and_belongs_to_many :tags, :join_table => :travels_tags
Heres some info from the docs to help explain the defsult behaviour for join table naming.
"By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order."
http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-join-table
A very similar question was already asked, bud I can't solve the problem anyway. I am trying to create a new record in rails console and I get this error:
2.1.2 :001 > subject = Subject.new
Mysql2::Error: Table 'simple_cms_development.subjects' doesn't exist: SHOW FULL FIELDS FROM `subjects`
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'simple_cms_development.subjects' doesn't exist: SHOW FULL FIELDS FROM `subjects`
Can somebody please very specifically tell my what should I do?
Here's subject.rb:
class Subject < ActiveRecord::Base
end
and schema.rb:
ActiveRecord::Schema.define(version: 20140617074943) do
create_table "admin_users", force: true do |t|
t.string "first_name", limit: 25
t.string "last_name", limit: 50
t.string "email", default: "", null: false
t.string "username", limit: 25
t.string "password", limit: 40
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "pages", force: true do |t|
t.integer "subject_id"
t.string "name"
t.string "permalink"
t.integer "position"
t.boolean "visible", default: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "pages", ["permalink"], name: "index_pages_on_permalink", using: :btree
add_index "pages", ["subject_id"], name: "index_pages_on_subject_id", using: :btree
create_table "sections", force: true do |t|
t.integer "page_id"
t.string "name"
t.integer "position"
t.boolean "visible", default: false
t.string "content_tipe"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "sections", ["page_id"], name: "index_sections_on_page_id", using: :btree
end
create_subjects.rb:
class CreateSubjects < ActiveRecord::Migration
def up
create_table :subjects do |t|
t.string "name"
t.integer "position"
t.boolean "visible" :default => false
t.timestamps
end
end
def down
drop_table :subjects
end
end
Add a comma in
t.boolean "visible" :default => false`
as in
t.boolean "visible", :default => false`
and then run rake db:migrate
Making sure that config/database.yml file has a valid entry for a database connection on your machine. Look at the development stanza.
More on migrations at guides.rubyonrails.org/migrations.html
More on configuring a database and the database.yml file at
http://edgeguides.rubyonrails.org/configuring.html#configuring-a-database
You need to create a subjects table that defines the attributes you want to persist in the Subject instances.
So say you want title and description. Use this command to create the migration:
rails generate migration subjects title:string description:text
And then run the command
rake db:migrate
Then try your Subject.new command
Alternatively, if you do not want to persist any subject attributes, change the subject class definition to:
class Subject
end