Rake db:seed refuses to insert data into a particular database column - ruby-on-rails

I’m having a very peculiar thing happen when I run a seed program to add users to my Rails app -- one of the columns absolutely refuses to be populated. It’s a user populate method, with some of the elements generated by the Faker gem.
The Faker items work just fine and insert into the database, except for the Faker::Avatar method. So I decided to try my own custom string with a randomly generated number for the avatar number. But nothing worked.
Here is the Users table from the schema:
create_table "users", force: :cascade do |t|
t.string "email", limit: 191, default: "", null: false
t.string "encrypted_password", limit: 191, default: "", null: false
t.string "reset_password_token", limit: 191
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 191
t.string "last_sign_in_ip", limit: 191
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name", limit: 45
t.string "last_name", limit: 45
t.string "username", limit: 30
t.string "location", limit: 191
t.text "profile", limit: 65535
t.string "avatar", limit: 191
end
And here is the seeding method for the User:
1.times do
user = User.create!(
first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
username: Faker::Internet.user_name,
email: Faker::Internet.safe_email,
password: Faker::Internet.password(8, 16),
location: Faker::Address.city + ', ' + Faker::Address.state,
profile: Faker::Lorem.sentence(rand(15..60)),
avatar: 'avatar' + Random.rand(1...180).to_s + '.jpg'
I am trying to figure out why I can't insert anything into the avatar column, either from Faker or my own string. It just seems strange!

This is caused by the uploader that is mounted to your avatar field.
The easiest solution is to comment out the mount_uploader line, seed the data and then uncomment the line.

If you look at the documentation for Ruby class Random here, the rand method does not support the signature you use. This should work if you change your code to:
avatar: 'avatar' + Random.rand(180).to_s + '.jpg'

Related

Why will a rake file used to seed a datbase not work due to foreign key constraints in Ruby on Rails?

I have created a dummy travel agency with Rails 6 and I am trying to use a rake file to seed data for ships, crusies and customer details etc.
The file: ships.rake looks like this:
namespace :ships do
desc "TODO"
task seed_cabins: :environment do
CreditCard.destroy_all
Address.destroy_all
Customer.destroy_all
Cruise.destroy_all
Ship.destroy_all
p "tables emptied"
5.times do |index|
Ship.create!(name: Faker::Coffee.blend_name, tonnage: Faker::Number.within(range: 10000..100000))
end
p "ships created"
# create cabins for each ship
ships = Ship.all
ships.each do |ship|
5.times do |index|
Cabin.create!(
ship_id: ship.id,
name: "Suite #{index+1}",
beds: Faker::Number.between(from: 1, to: 3),
deck: Faker::Number.between(from: 1, to: 3)
)
end
end
p "Cabins created"
ships = Ship.all
ships.each do |ship|
2.times do |index|
Cruise.create!(
ship_id: ship.id,
name: Faker::Hacker.adjective.capitalize + " " +Faker::Hacker.noun.capitalize+" Cruise"
)
end
end
#create customers
3.times do |index |
Customer.create!(
first_name:Faker::Name.first_name,
last_name:Faker::Name.last_name,
has_good_credit: true,
paid: false
)
end
#give each customer an addresses and credit card
customers = Customer.all
customers.each do | customer|
Address.create!(
street:Faker::Address.street_address,
city:Faker::Address.city,
postcode:Faker::Address.postcode,
customer_id: customer.id
)
year = [2020, 2021,2022, 2023]
organisations =["American Express", "MasterCard", "Visa"]
CreditCard.create!(
customer_id:customer.id,
number:Faker::Number.number(12),
exp_date:year.sample.to_s + "/" + Faker::Number.between(1,12).to_s,
name_on_card: customer.first_name + " " + customer.last_name,
organisation: organisations.sample.to_s
)
end
p "customers created"
end
end
The database schema looks like this:
ActiveRecord::Schema.define(version: 2020_10_27_221059) do
create_table "addresses", force: :cascade do |t|
t.string "street"
t.string "city"
t.string "postcode"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_addresses_on_customer_id"
end
create_table "cabins", force: :cascade do |t|
t.string "name"
t.integer "beds"
t.integer "deck"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cabins_on_ship_id"
end
create_table "credit_cards", force: :cascade do |t|
t.string "number"
t.string "exp_date"
t.string "name_on_card"
t.string "organisation"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_credit_cards_on_customer_id"
end
create_table "cruises", force: :cascade do |t|
t.string "name"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cruises_on_ship_id"
end
create_table "customers", force: :cascade do |t|
t.string "last_name"
t.string "first_name"
t.integer "has_good_credit"
t.boolean "paid"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "harbours", force: :cascade do |t|
t.string "name"
t.string "country"
t.string "lat"
t.string "long"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "ships", force: :cascade do |t|
t.string "name"
t.integer "tonnage"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "addresses", "customers"
add_foreign_key "cabins", "ships"
add_foreign_key "credit_cards", "customers"
add_foreign_key "cruises", "ships"
end
Essentially, I am just try to run the command: rake ships:seed_cabins and try to generate the data fresh. However, I keep getting the following error:
rake aborted!
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Caused by:
SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Tasks: TOP => ships:seed_cabins
(See full trace by running task with --trace)
I am aware the order of when the tables are destroyed is an issue and the current order is the closest I can get to the file working. it seems to be the Ship.destroy_all line that is the issue because when I remove it and run the file it runs with no issues!
However, as far as I can see there would be no constraints left on that database once the other tables are cleared that would prevent Ship from being deleted?
If anyone could point me in the right direction I would be very grateful.
You missed destroying the cabins, which are still referencing the ships as foreign key. Hence the foreign key constraint is kicking in.
On a side note, you can make your life easier by adding dependent: :destroy in your associations. For example, in your Ship model, you would add,
class Ship < ApplicationRecord
has_many :cabins, dependent: :destroy
end
Since a cabin doesn't make sense without the corresponding ship. What this will do is, whenever a Ship instance is destroyed, it will destroy the related cabins as well.

Removing SQLite Table with singular name from Rails

So I'm working on migrating into a SQLite db on Rails and somehow ended up with User and Users tables. How do I remove it without removing Users?
create_table "user", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.string "password"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.string "password"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
May not be best practice, but what seems to have solved it for me was to delete from the schema,drop the databaserails db:dropcreate a new onerails db:create and migrate rails db:migrate
Good to go as far as I can tell!

Issues with Rails 6 test

I am using ruby 2.7 and Rails version 6.0.2.1
When I try to test my model I get this message
Error:
OfferTest#test_valid_offer:
DRb::DRbRemoteError: PG::UndefinedTable: ERROR: relation "views" does not exist
LINE 8: WHERE a.attrelid = '"views"'::regclass
^
(ActiveRecord::StatementInvalid)
rails test test/models/offer_test.rb:4
This is my schema file:
ActiveRecord::Schema.define(version: 2020_01_20_105655) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "offers", force: :cascade do |t|
t.string "city"
t.string "area"
t.string "address"
t.string "contact_person"
t.string "contact_person_phone"
t.string "denomination"
t.string "category"
t.string "typology"
t.integer "guests"
t.integer "rooms"
t.boolean "lift"
t.decimal "expense"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "requests", force: :cascade do |t|
t.string "name"
t.string "last_name"
t.string "address"
t.decimal "budget"
t.date "date_of_request"
t.string "document_id"
t.string "phone"
t.string "residential_address"
t.date "date_of_birth"
t.string "notes"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "name", null: false
t.string "last_name", null: false
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.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
Ad of now I have 3 tables. I am testing the Offer model but I get this strange behaviour.
This is my test model code
require 'test_helper'
class OfferTest < ActiveSupport::TestCase
test "valid offer" do
offer = Offer.new(city: "Rome", area: "Zona Sud", address: "Via Roma")
end
end
I've already run rails db:test:prepare but I cannot fix this issue.
My initial thought is that some gem is injecting behaviour into your models.
Something is expecting a table "views". The name views hints at either a gem using database views to virtualize tables, or some gem that works in the domain with views: for example a gem for statistics (An order has been viewed 21 times: has 21 views).
I'd suggest removing all gems from your gemfile and re-including them one by one. This will tell you what gem is injecting this behaviour: knowing what your dependencies do is an important part of building an app, IMO.
If it is a gem, that gem most probably has some migrations that you need to install and run:
bundle exec rake railties:install:migrations
bundle exec rake db:migrate

PG::DuplicateColumn: ERROR: column "product_id" of relation "users" already exists

I have seen this question posted several times and the solution is always to drop the database and recreate it. I have data in my database and hence do not want to do that.
Schema:
create_table "users", force: :cascade 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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "product_id"
end
My second to last migration file:
class AddProductIdToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :product_id, :string
end
end
I have no other migration file that creates a product_id column on my current branch.
I have multiple branches with different database schema. I am wondering if that caused the issue. The branch that might have created the product_id is only there for reference now. It will not be merged to master.
How do I fix this issue? I have tried:
rake db:rollback step=3
rake db:migrate
but that did not work.
Your create_table is already creating product_id inside the database.
create_table "users", force: :cascade 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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "product_id" // <- note this line
end
And you are trying to add another column of same name in your table, which raises an error.

generating meaningful usernames in devise

I'm trying to have my app automatically generate usernames to be used as the url. Typically they will be the users first and last name added together however when there already exists a user with the same first and last name it will append a number to the name that increases for each.
This is the method i created:
def full_name
first_name + ' ' + last_name
end
def user_name
t_user_name = first_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '') + last_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '')
user_name = t_user_name
num = 1
while User.find_by_user_name(user_name).count > 0
num += 1
user_name = "#{t_user_name}#{num}"
end
end
I'm currently getting the error:
undefined method `find_by_user_name'
Which i thought would work automatically?
I was also trying to examples shown in this post:
generate unique username (omniauth + devise)
but I kept getting the error:
Mysql2::Error: Unknown column 'users.login' in 'where clause': SELECT COUNT(*) FROM `users` WHERE `users`.`login` = 'bobweir'
Even though I added
t.string :login, null: false, default: ""
to the users table
edit2: schema.rb
ActiveRecord::Schema.define(version: 20150611033237) do
create_table "users", force: :cascade do |t|
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
Rails achieves find_by_sth magic by inferring an attribute name in your method call, thus returning an ActiveRecordRelation.
As you have no user_name attribute in your model, Active Record will not be able to perform a search on it (just imagine it has to be translated into an SQL query).
On the other hand, I'd re-think the logic of your user_name method if I were you. Consider persisting the user_name on your database.
By the way, in the second error you mention, notice that the example you have is working with a login attribute, which you simply don't have.

Resources