Ruby on Rails id column not generated after db:migration - ruby-on-rails

I'm following a course on coursera and I'm on my first assignment details of which can be found on this and this link. WHen I ran rspec I found the test cases to be failing, turned out my schema didn't have an ID column in it. In the course it said that when I run migration the ID column is generated automatically just like created_at and updated_at. Anyone has any idea why the id column probably didn't get generated. I know I can overcome the problem by specifying it in a new migration but just wanted to know the reason.
Here's the Schema I currently have:
ActiveRecord::Schema.define(version: 20161108162529) do
create_table "profiles", force: :cascade do |t|
t.string "gender"
t.integer "birth_year"
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "todo_items", force: :cascade do |t|
t.date "due_date"
t.string "title"
t.text "description"
t.boolean "completed", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "todo_lists", force: :cascade do |t|
t.string "list_name"
t.date "list_due_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
This is the migrations for todolists:
class CreateTodoLists < ActiveRecord::Migration
def change
create_table :todo_lists do |t|
t.string :list_name
t.date :list_due_date
t.timestamps null: false
end
end
end
The model class it generated:
class TodoList < ActiveRecord::Base
end
My method that is inserting a record in it in the assignment.rb file as asked:
def create_todolist(params)
# accept a hash of todolist properties (`:name` and `:due_date`) as an input parameter. Note these are not 100% the same as Model class.
# use the TodoList Model class to create a new user in the DB
# return an instance of the class with primary key (`id`), and dates (`created_at` and `updated_at`) assigned
t1 = TodoList.new
t1.list_name = params["name"]
t1.list_due_date = params["due_date"]
t1.save
TodoList.first
end
rspec code that is failing:
context "rq03.2 assignment code has create_todolist method" do
it { is_expected.to respond_to(:create_todolist) }
it "should create_todolist with provided parameters" do
expect(TodoList.find_by list_name: "mylist").to be_nil
due_date=Date.today
assignment.create_todolist(:name=> 'mylist', :due_date=>due_date)
testList = TodoList.find_by list_name: 'mylist'
expect(testList.id).not_to be_nil
expect(testList.list_name).to eq "mylist"
expect(testList.list_due_date).to eq due_date
expect(testList.created_at).not_to be_nil
expect(testList.updated_at).not_to be_nil
end
Actual message that I get when it fails the test:
Failures:
1) Assignment rq03 rq03.2 assignment code has create_todolist method should create_todolist with provided parameters
Failure/Error: expect(testList.id).not_to be_nil
NoMethodError:
undefined method `id' for nil:NilClass
# ./spec/assignment_spec.rb:173:in `block (4 levels) in <top (required)>'
# ./spec/assignment_spec.rb:14:in `block (2 levels) in <top (required)>'

The schema won't show the ID column. I double checked with one of my rails apps:
db/schema.rb
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "first_name"
t.string "last_name"
end
And when I describe the table in Postgres with \d users, I see the id column:
Column | Type | Modifiers
------------------------+-----------------------------+----------------------------------------------------
id | integer | not null default nextval('users_id_seq'::regclass)
email | character varying | not null default ''::character varying
first_name | character varying |
last_name | character varying |
If there is a reason you don't want the ID, you can omit it by passing id: false to create_table.
create_table :users, id: false do |t|
#...
end
Probably a horrible idea on the users table :-)
Update
Looks like you are not actually creating a new TodoList.
The clue here is in the error: "undefined method 'id' for nil:NilClass". Your testList is nil.
One good tip is to always use the ActiveRecord's "bang" methods in tests. This will cause them to throw an exception if they fail. Which is super helpful when trying to track down errors -- you'll find the place with the actual error and not some side effect down the line.
I bet you can update your create_todolist to help track this down
def create_todolist(params)
# Updated: To use ActiveRecord create! method.
# This will throw an exception if it fails.
TodoList.create!(list_name: params[:name], due_date: params[:due_date])
end
I would also update your spec, by changing:
testList = TodoList.find_by list_name: 'mylist'
To use the bang:
testList = TodoList.find_by! list_name: 'mylist'

Related

"joins" with two tables does not work because of "ActiveModel::MissingAttributeError"

I am writing my application on Ruby-on-Rails and I have a problem with "joins". There are 3 tables: todo_lists, users, statuses. Each todo has one user and one status and they are introduced as IDs. And I want to get the whole todo with status name and user name instead of their IDs. This is how I tried to do that:
TodoList.joins(:user, :status)
.select("
todo_lists.id,
todo_lists.title,
todo_lists.description,
statuses.name,
users.name,
todo_lists.deadline,
todo_lists.is_disabled")
.as_json
But this throws an MissingAttribute error: missing attribute: status_id. But I added user_id and status_id records to my todo_lists table before that. What I must to do to solve this?
user.rb, status.rb, todo_list.rb files:
class User < ApplicationRecord
has_many :todo_lists
end
class Status < ApplicationRecord
has_many :todo_lists
end
class TodoList < ApplicationRecord
belongs_to :status
belongs_to :user
end
schema.rb file:
ActiveRecord::Schema.define(version: 2020_03_17_071204) do
create_table "statuses", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "todo_lists", force: :cascade do |t|
t.string "description", null: false
t.integer "user_id", default: 1, null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.boolean "is_disabled"
t.datetime "deadline"
t.string "title", null: false
t.integer "status_id", default: 1, null: false
end
create_table "users", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "todo_lists", "statuses"
add_foreign_key "todo_lists", "users"
end
The most interesting is that if I joins with only users table, everything works fine :)
The full stack trace:
ActiveModel::MissingAttributeError (missing attribute: status_id):
app/controllers/todos_controller.rb:75:in `get_all_todos'
app/controllers/todos_controller.rb:3:in `get'
And todos_controller.rb methods where I am using "joins":
def get
render :json => get_all_todos
end
def get_all_todos
TodoList.joins(:status, :user)
.select("
todo_lists.id,
todo_lists.title,
todo_lists.description,
statuses.status,
todo_lists.deadline,
todo_lists.is_disabled")
.as_json
end
Joins are performed on a related column between two or more tables.
In the configuration that you have given, you are trying to join todo_lists to users and statuses table, but there is no relationship column to join on.
At the same time, the reason todo_lists join with users works because the join is performed on user_id column of todo_lists.
ActiveRecord::MissingAttributeError is raised because it cannot find this related column to join these two tables with, I am not sure about your applications specific domain logic, but you can fix this by adding user_id foreign_key to todo_lists table.

Create not saving record due to non-existent field

Can't figure this out. I'm running Postgres on a Ruby app and my schema looks like this:
ActiveRecord::Schema.define(version: 20180518200146) do
create_table "amazons", force: :cascade do |t|
t.text "auth_token"
t.text "marketplace"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "shop_id"
t.boolean "three_speed"
t.text "seller_id"
t.string "shipping_countries", array: true
end
create_table "shops", force: :cascade do |t|
t.string "shopify_domain", null: false
t.string "shopify_token", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "paid", default: false
t.boolean "setup", default: false
t.string "carrier_id"
t.index ["shopify_domain"], name: "index_shops_on_shopify_domain", unique: true
end
add_foreign_key "amazons", "shops"
end
I did remove shopify_domain from the Amazons table. But I ran that migration and as you can see in my schema its gone.
However I try and create a new record and I get this error message:
NoMethodError (undefined method shopify_domain for #<Amazon:0x000000041fb9c8>
I'm creating the new Amazon record, by scoping it to the shop like this:
current_shop.amazons.create(
marketplace: marketplace,
seller_id: seller_id,
auth_token: auth_token,
shipping_countries: countries,
shop_id: current_shop.id)
With current_shop being a method that gets the current shop from the session. It works fine.
Where did I go astray?
EDIT: I went and checked PG to be sure, and the field isn't their either. Here is what PG has:
id | bigint | not null default nextval('amazons_id_seq'::regclass)
auth_token | text |
marketplace | text |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
shop_id | integer |
three_speed | boolean |
seller_id | text |
shipping_countries | character varying[] |
EDIT: Here is the Amazon model
class Amazon < ActiveRecord::Base
include ShopifyApp::SessionStorage
belongs_to :shop
end
And then this is the entire error message:
NoMethodError (undefined method `shopify_domain' for #
<Amazon:0x000000041fb9c8>
Did you mean? shop_id_change):
app/controllers/concerns/amazon_creds_concern.rb:55:in `save_amazon_creds'
app/controllers/concerns/amazon_creds_concern.rb:23:in `create_amazon_client'
app/controllers/amazon_creds_controller.rb:9:in `amazon_credentials_check'
And then the lines of code that match the error message, starting from the bottom up: app/controllers/amazon_creds_controller.rb:9:in amazon_credentials_check
render json: {amazon_creds_status: create_amazon_client(marketplace, seller_id, auth_token, countries), countries: countries.blank?}
Then app/controllers/concerns/amazon_creds_concern.rb:23:in
save_amazon_creds(marketplace, seller_id, auth_token, countries)
Finally app/controllers/concerns/amazon_creds_concern.rb:55:in
current_shop.amazons.create(
marketplace: marketplace,
seller_id: seller_id,
auth_token: auth_token,
shipping_countries: countries,
shop_id: current_shop.id)
include ShopifyApp::SessionStorage
adds
validates :shopify_domain, presence: true, uniqueness: true
to your Amazon class.
You either need the shopify_domain in that class (or use a forward) or you need to remove the include from the Amazon class.
Same for shopify_token by the way.
https://github.com/Shopify/shopify_app/blob/master/lib/shopify_app/session/session_storage.rb

accepts_nested_attributes - ActiveRecord::UnknownAttributeError

I have a very simple model that each event has many forexes. I am trying to create a nested form to create new event with a bunch of forexes in a go.
class Event < ActiveRecord::Base
has_many :forexes
accepts_nested_attributes_for :forexes
end
class Forex < ActiveRecord::Base
belongs_to :event
end
The schema is like this:
ActiveRecord::Schema.define(version: 20180505093823) do
create_table "events", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "base"
end
create_table "forexes", force: :cascade do |t|
t.string "code"
t.float "rate"
t.integer "event_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "forexes", ["event_id"], name: "index_forexes_on_event_id"
end
And then I tried to create new objects using the following code in rails console. It fails.
Event.new( name: "11", base: "HKD", forexes_attributes: [ {code: "RMB", rate:1}, {code: "CNY",rate:2}])
It throws me back with this error.
ActiveRecord::UnknownAttributeError: unknown attribute 'forexes_attributes' for Event.
I know this is quite a basic question. And I have tried many different ways after researching in different places. I couldn't debug it. Appreciate your help.
In your Event controller you need to include the forexes_attributes in event_params method as along with default one
def event_params
params.require(:event).permit(forexes_attributes: Forexes_attribute_names.map(&:to_sym).push(:_destroy))
end

Seeding a rails model with an array in rails

I understand that the answer may be in similar answers that I've read but I do not yet have the knowledge power to draw a solution from them.
I'm trying to seed a column in a rails model with an array:
["N1", "N2", "N3", "N4", "N5", etc ]
Each value will represent a new line (or entry? not sure of the correct terminology) in the database column.
Currently, similar to what has been suggested in a similar posts, I'm using:
[above array].each do |pc|
Postcodes.create!({ pcode => pc})
end
But I'm getting the following error:
NameError: uninitialized constant Postcodes
I've tried un-pluralising the model name and also un-capitalising but this does not seem to help.
db:schema:
ActiveRecord::Schema.define(version: 20151211095938) do
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Model:
class Postcode < ActiveRecord::Base
end
Your model is names Postcode, not Postcodes (not the plural s). The following should work:
codes = ["N1", "N2", "N3", "N4", "N5"]
codes.each do |code|
Postcode.create!(pcode: code)
end

new record in rails console error

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

Resources