Create not saving record due to non-existent field - ruby-on-rails

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

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.

Ruby on Rails id column not generated after db:migration

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'

Rails5 - How to db:setup new machine and include database autoincrement id sequences

I have a Rails5 api that was built from scratch and all of my models' database sequences for id autoincrement where automatically created. When a colleague attempted to db:setup the database on a fresh machine, the schema was loaded, but the sequences were not created and, therefore, our db:seeds were unable to be added because there is a "not null" constraint on the tables.
The original table id column looks like this
id | integer | not null default nextval('users_id_seq'::regclass) | plain |
After running db:setup, the "new" database on the fresh machine looks like this
id | integer | not null | plain |
I've never had this issue with previous Rails versions and wonder if it may be a v5 issue. What are we doing wrong?
Thanks for any tips!!
On the new database, there are no sequences shown in postgres when running "\ds;"
The migration for the users table looks looks like this
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name, limit: 25
t.string :last_name, limit: 25
t.string :mobile_phone, limit: 25
t.string :auth_token, limit: 36
t.integer :failed_login_attempts, limit: 2, :default => 0
t.boolean :account_locked, :default => false
t.timestamps
end
end
end
schema.rb for this table looks like this ( after some later migrations )
create_table "users", id: :integer, force: :cascade do |t|
t.string "first_name", limit: 25
t.string "last_name", limit: 25
t.string "mobile_phone", limit: 25
t.string "auth_token", limit: 36
t.integer "failed_login_attempts", limit: 2, default: 0
t.boolean "account_locked", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null:
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
end

Active Record Associations to prevent duplicate database entries

I am setting up a Ruby on Rails application where a User will have an Album collection. My initial thinking was to set it up with a simple User has_many Albums and Albums belongs to Users. The problem that arises here is that the Album table will have duplicates entries, only distinguished by user_id.
id | album_name | artist_id | created_at | updated_at | user_id
-----+-------------+-----------+----------------------------+----------------------------+---------
2 | SuperRando | 3 | 2015-11-13 00:03:51.790759 | 2015-11-13 00:03:51.790759 | 1
3 | SuperRando | 3 | 2015-11-13 00:19:08.438907 | 2015-11-13 00:19:08.438907 | 2
So what would be the best course of action so I could have an Album table with all unique albums?
You could model it using a join table:
class Album < ActiveRecord::Base
has_many :user_albums
has_many :users, through: :user_albums
end
class User < ActiveRecord::Base
has_many :user_albums
has_many :albums, through: :user_albums
end
class UserAlbum < ActiveRecord::Base
belongs_to :user
belongs_to :album
end
So, your schema would like somewhat like this:
create_table "albums", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "user_albums", force: :cascade do |t|
t.integer "user_id"
t.integer "album_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Now, the way you would call this code in your controller or console. you can do this:
Create User: user = User.create(params)
Find or Create an album: album = Album.find_or_create_by(params)
Associate user with that album user.albums << album & then save it by user.save
Now to see user's album. you can do:
User.take.albums
to see users of a particular album, you can do
Album.take.users
Hope this answers your question.
For more information have a look at the rails guides:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Postgres Rails Adapter is thinking Bigint/Varchar is Integer - causes exception when saving

Update: This is regarding Rails 4.x and is not an issue in Rails 5.
I have a Number model which a number field that is a bigint. The schema.rb file correctly creates the table structure in the database.
However using the app, when I go to create a new Number, I get an error saying:
RangeError at /numbers
71731224865 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 4
Why is this number field still being treated as a standard integer rather than a bigint?
This seems different to the other "out of range" errors on StackOverflow as they all seem to not be able to get the field defined as bigint in the database in the first place. However, I've got that.. this seems to be "on save" the adapter is freaking out.
Here's the create_table as it appears in schema.rb:
create_table "numbers", id: false, force: :cascade do |t|
t.bigint "number", null: false, index: {name: "index_numbers_on_number", unique: true}
t.string "formatted_number"
t.text "description"
t.integer "user_id", null: false, index: {name: "index_numbers_on_userid"}, foreign_key: {name: 'fk_numbers_user_id'}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Update 1: I've recreated the column as a DECIMAL(11,0) in the hopes that'd be a temporary workaround, however that failed too with the same error! Maybe the only option I have as a workaround is VARCHAR(11).
Update 2: Ok. Something weird is going on. I've defined the field now as VARCHAR(11) so I can keep progressing with work... but that fails with the same error too. What the?
Update 3: Could it be because the number field in the numbers table is the Primary Key? I'm not using a id as the key, I've overridden it. Not that I'm trying to use the field as VARCHAR, it makes no sense why the PostgreSQLAdaptor is still showing ... is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 4 error.
Here's my Number model if it helps:
class Number < AbstractModel
belongs_to :user
has_many :extensions
self.primary_key = 'number'
validates :number, numericality: { only_integer: true, greater_than_or_equal_to: 611, less_than_or_equal_to: 61999999999 }, presence: true, uniqueness: true
validates :user_id, presence: true
end
Update 4: Using the Rails Console to see what data type it thinks the columns is, and it says INTEGER! Grr. sql_type does return BIGINT though. What the?
Loading development environment (Rails 4.2.1)
irb(main):001:0> Number.column_for_attribute('number').type
=> :integer
irb(main):002:0> Number.column_for_attribute('number').sql_type
=> "bigint"
irb(main):003:0> quit
Making sure the DB is still setup as expected:
[turgs#web123 myapp]$ psql -h 127.0.0.1 -p 5432
psql (9.1.15)
db=> \d numbers
Table "public.numbers"
Column | Type | Modifiers
------------------+-----------------------------+-----------
number | bigint | not null
formatted_number | character varying |
description | text |
user_id | integer | not null
max_extn_length | integer |
created_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
Indexes:
"index_numbers_on_number" UNIQUE, btree (number)
"index_numbers_on_userid" btree (user_id)
Referenced by:
TABLE "extensions" CONSTRAINT "fk_extensions_number_id" FOREIGN KEY (number_id) REFERENCES numbers(number)
db=>
Update 5: Yes.... another update! This time I thought I'd fall on my sword and try what everyone uses in the other posts where they can't get the BIGINT to create in the database in the first place. So, I changed by schema.rb to:
create_table "numbers", id: false, force: :cascade do |t|
t.integer "number", limit: 8, null: false, index: {name: "index_numbers_on_number", unique: true}
t.string "formatted_number"
t.text "description"
t.integer "user_id", null: false, index: {name: "index_numbers_on_userid"}, foreign_key: {name: 'fk_numbers_user_id'}
t.integer "max_extn_length"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Note the t.integer "number", limit: 8. Surprisingly, that DID create a bigint field in the database still. My hopes were high. Unfortunately, no cigar. Same error when saving value.
Try
t.column :number, :bigint
See :
Rails Migration: Bigint on PostgreSQL seems to be failing?
create_table :numbers do |t|
t.bigint :mynumber
t.timestamps
end
i tried with the above migration it works for the following length of number
7173122486511111111
i think there is a problem with the version
please update your postgres/rails version

Resources