RSpec changing model attribute name - ruby-on-rails

Not the value, the name of the attribute. Yes, for real. I don't know what the hell is going on.
The migration:
class CreateFolders < ActiveRecord::Migration
def change
create_table :folders do |t|
t.string :name, null: false
t.timestamps
end
change_table :bookmarks do |t|
t.belongs_to :folder
end
end
end
The Schema:
ActiveRecord::Schema.define(version: 20140424065045) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "bookmarks", force: true do |t|
t.string "name", null: false
t.string "url", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "folder_id"
end
create_table "folders", force: true do |t|
t.string "name", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
end
What it shows inside of rails c:
[3] pry(main)> Bookmark
=> Bookmark(id: integer, name: string, url: string, created_at: datetime, updated_at: datetime, folder_id: integer)
And now, our huge glaring problem:
[3] pry(#<RSpec::Core::ExampleGroup::Nested_2::Nested_1>)> Bookmark
=> Bookmark(id: integer, name: string, url: string, created_at: datetime, updated_at: datetime, folders_id: integer)
Notice the name of the last attribute there: folders_id
Does anyone know what in the hell could ever cause this?

Finally found what the issue was, and damn is it bizarre.
So brand new in Rails 4, is ActiveRecord::Migration.maintain_test_schema!. This convenient little tool is pretty nice, however it only updates the test schema on creation of a new migration. In the process, if you get a migration wrong the first time, and update it later, you'll find inconsistencies like this.
To fix the problem, run rake db:test:prepare. You'll get a deprecation warning, but ignore it. When you check inside of rspec again it should work fine.

Related

Rails 6, how can I create custom primary key with migration?

I am trying to create custom primary key in rails 6, but didn't created primary key,
it's created normal id.
migration i have given
def change
create_table(:m_user_status, :id => false) do |t|
t.integer :id, :options => 'PRIMARY KEY'
t.string :status_name, limit: 20
t.integer :status_check
t.timestamps
end
from above just created id with int4 type, but i want create id with type int4 and primary key without auto-increment.
how i give id without auto-incremented and type int4(integer normal)
You can combine the :id and :primary_key options according to the docs here: https://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/create_table
For example:
class CreatedummyTable < ActiveRecord::Migration[6.0]
def change
create_table :dummy_table, id: :int4, primary_key: :foo do |t|
t.timestamps
end
end
end
Creates this schema in postgres:
create_table "dummy_table", primary_key: "foo", id: :integer, default: nil, force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

Rails ActiveRecord writes encrypted attribute but does not read it

I have a Patient model backed by a patients Postgres database table. It has an attribute national_id that is encrypted by the lockbox gem and therefore stored in the national_id_ciphertext column. This attribute is saved/updated fine and I can verify this in the database.
However when I read this record back, the national_id attribute is not included.
Rails console:
pry(main)> p = Patient.find(8)
=> #<Patient id: 8, name: "Øyvind Hansen", address: nil, address_directions: nil, zip: "0667", city: "Oslo", phone_number: "+4712345678", email: "oyvind#test.com", created_at: "2020-09-05 19:41:55", updated_at: "2020-09-05 20:45:46", referral_id: nil>
pry(main)> p.national_id
=> "12345678912"
The schema is:
create_table "patients", force: :cascade do |t|
t.string "name"
t.string "address"
t.string "zip"
t.string "city"
t.string "phone_number"
t.string "email"
t.text "national_id_ciphertext" # Saved, but not retrieved
t.bigint "referral_id"
t.index ["referral_id"], name: "index_patients_on_referral_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
The implementation of Lockbox encryption is very simple and straight from the basic example from the docs.
class Patient < ApplicationRecord
encrypts :national_id
end
Any idea why the national_id accessor created by Lockbox are not included in enumerable model attributes?
As you noted in your own test, the value is available. national_id is an available method on the object but is not a DB attribute. You can always retrieve it with dot notation e.g. my_patient.national_id but not through hash notation
my_patient.national_id
=> "12345678912"
my_patient["national_id"]
=> nil
This shouldn't normally be a problem, just use dot notation.
If the problem is transposing into json you can add methods to your json call...
my_patient.to_json(methods: [:national_id])
Or you can modify your to_json to include it always
class Patient < ActiveRecord
def to_json(options={})
super options.merge({methods: [:national_id]})
end
end

How should I name and make foreign keys in Rails 5.1?

I'm just getting my start in developing in Rails so I thought I'd make an expense-tracking app for my family. As I'm sure will become obvious, I'm still wrapping my head around creating several database tables and having them all link together correctly. I've completed the Hartl rails tutorial but this is my first stab at making my own thing.
The core of the app is a collection of Expenses. Each Expense has an amount, a date, a reference to table of Vendors, and a reference to a table of ExpenseTypes. The problem is, I've generated an Expense through database seeds, but it doesn't refer to the entries in the other tables correctly:
This how I'm creating it, as the last entry in seeds.rb:
Expense.create!(amount: 500, date: Date.today, vendor_id: Vendor.first, expensetype_id: ExpenseType.second, note: "This is the first expense!")
But when I go into the console to examine it:
2.3.4 :002 > Expense.first
Expense Load (0.2ms) SELECT "expenses".* FROM "expenses" ORDER BY "expenses"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Expense id: 1, amount: 500, date: "2018-01-08", vendor_id: nil, expensetype_id: nil, note: "This is the first expense!", created_at: "2018-01-08 09:37:19", updated_at: "2018-01-08 09:37:19">
I suspect it's because the tables are a little awkwardly named, but I don't have enough experience to know what's going on for sure. I tried naming my classes in CamelCase and generating migrations through "rails generate migration", but I'm not sure what kind of replacing and searching it's doing based on underscores and pluralization in the table and class names.
Here's schema.rb:
create_table "expense_types", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_expense_types_on_name"
end
create_table "expenses", force: :cascade do |t|
t.integer "amount", null: false
t.date "date"
t.integer "vendor_id"
t.integer "expensetype_id"
t.string "note"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["expensetype_id"], name: "index_expenses_on_expensetype_id"
t.index ["vendor_id"], name: "index_expenses_on_vendor_id"
end
create_table "vendors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_vendors_on_name"
end
And here's the rest of seeds.db:
# Vendors
vendor_list = ["Vendor 1", "Vendor 2", "Vendor 3", "Vendor 4"]
vendor_list.each do |item|
Vendor.create!(name: item)
end
#Expense types
expense_type_list = ["Daily groceries", "Eating out", "Travel", "Present"]
expense_type_list.each do |item|
ExpenseType.create!(name: item)
end
And finally, expense.rb, which was automatically generated:
class Expense < ApplicationRecord
belongs_to :vendor
belongs_to :expensetype
end
Maybe that should be has_one? I tried changing it but there wasn't any difference. I'm a bit sheepish about generating migrations to change the Expense table since I don't want to fill up the folder with pointless or broken migrations and I'm still not very adept at using them.
Am I forgetting something significant? Is there a migration I can generate that will let everything hook into each other correctly? Thanks for any help you can give!
First, you have to update your Expense model:
class Expense < ApplicationRecord
belongs_to :vendor
belongs_to :expense_type
end
As it should be expense_type not expensetype - you have to respect the model name.
Second, you are creating expense but you pass an object as id. If you are referencing to vendor_id then pass id, if to vendor then pass an object:
Expense.create!(amount: 500, date: Date.today, vendor: Vendor.first, expense_type: ExpenseType.second, note: "This is the first expense!")
To sum up things, I found two problems:
You misspelled ExpenseType model name in association and in Expense.create!
You pass an object to vendor_id and expense_type_id

Rails 4 SQLiteException

I am running into SQLiteException that seems to be causing problem.
Schema.rb
create_table "features", force: :cascade do |t|
t.string "name_key"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "features", ["name_key"], name: "index_features_on_name_key"
create_table "organizations", force: :cascade do |t|
t.string "name"
t.string "code"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "organizations_features", id: false, force: :cascade do |t|
t.integer "organization_id"
t.integer "feature_id"
end
This is current schema and i explicity created table organizations_features(still through migration but a separate migration that references a join table) as otherwise create_join_table would create "features_organizations". In that process, if i run
rake db:drop db:create db:schema:load
I still keep getting the following error even without loading a single record in any tables(i never ran db:seed).
ActiveRecord::StatementInvalid: SQLite3::SQLException: near ")": syntax error: INSERT INTO "organizations_features" () VALUES ()
The other question seem to suggest to make the join table name all singular as in organization_feature, but since we share the schema with other services, it is imperative that we use the same naming conventions.
Note: even i tried to create table using migration "create_join_table" the problem seem to persist"
Update : seeds.rb
organization = Organization.create!(name: 'XYZ', code: 'xyz')
feature = Feature.create!(name_key: 'Some Feature')
user = User.create!(name: "user1",
email: "user#abcd.org",
password: "password123",
password_confirmation: "password123",
profile_id: profile.id)
OrganizationsFeature.create!(feature_id: feature.id, organization_id: organization.id)
where OrganizationsFeature looks like this
class OrganizationsFeature < ActiveRecord::Base
belongs_to :organization
belongs_to :feature
end
I found answer to the question in case if someone else runs into the same issue. The test/fixtures/organizations_features.yml file has null records
one :{}
two: {}
which was causing null records to be inserted into the table. This data is loaded every time and hence insert error.
Having proper data/deleting the file solved the issue.

unexpected attributes found in Active Record object

I am finding an unexpected attribute in an ActiveRecord object and I can't figure out where its coming from. Note the final attribute nil => nil.
irb(main):001:0> p = ProgExit.new
=> #<ProgExit id: nil, Student_Bnum: nil, Program_ProgCode: nil, ExitCode_ExitCode: nil, ExitTerm: nil, ExitDate: nil, GPA: nil, GPA_last60: nil, RecommendDate: nil, Details: nil>
irb(main):002:0> p.attributes
=> {"id"=>nil, "Student_Bnum"=>nil, "Program_ProgCode"=>nil, "ExitCode_ExitCode"=>nil, "ExitTerm"=>nil, "ExitDate"=>nil, "GPA"=>nil, "GPA_last60"=>nil, "RecommendDate"=>nil, "Details"=>nil, nil=>nil}
Two other items of note: 1) this problem doesn't present for any other models. 2) this problem is the same for this model across development, test and production. 3) The model does not use attr_accessor anywhere.
Any idea where this comes from? I am including the related model though it is thus far tiny (still working on it).
class ProgExit < ActiveRecord::Base
belongs_to :student, foreign_key: "Student_Bnum"
belongs_to :program, foreign_key: "Program_ProgCode"
belongs_to :exit_code, foreign_key: "ExitCode_ExitCode"
end
And here is the relevant code from my schema.rb
create_table "prog_exits", id: false, force: true do |t|
t.integer "id", null: false
t.string "Student_Bnum", limit: 9, null: false
t.string "Program_ProgCode", limit: 45, null: false
t.string "ExitCode_ExitCode", limit: 45, null: false
t.integer "ExitTerm", null: false
t.datetime "ExitDate"
t.float "GPA", limit: 24
t.float "GPA_last60", limit: 24
t.datetime "RecommendDate"
t.text "Details"
end
add_index "prog_exits", ["ExitCode_ExitCode"], name: "fk_Exit_ExitCode1_idx", using: :btree
add_index "prog_exits", ["Program_ProgCode"], name: "fk_Exit__Program_idx", using: :btree
add_index "prog_exits", ["Student_Bnum"], name: "fk_Exit_Student1_idx", using: :btree
add_index "prog_exits", ["id"], name: "id", using: :btree
I'm not sure what other code to include here but if there is something else that might be the culprit I can share that to.
since you've overriden the default primary key for this table (by including the id: false option in the create_table statement), you need to explicitly define a primary key for this model.
Per Rails docs, you can use self.primary_key= on the model to define the key explicitly.
see related issue: ActiveRecord model without primary key

Resources