I can add a column with custom data type using the following code
def change
add_column :assessorials, :metric_type, :assessorial_metric_type
end
The above code adds a new metric_type column of type assessorial_metric_type to the assessorials table
Now i have to create a new table which contains a column metric_type of type assessorial_metric_type
I have tried the following code.
create_table :charges do |t|
t.string :title
t.assessorial_metric_type :metric_type
end
This gives the error
undefined method `assessorial_metric_type' for #<ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition:
Any idea on how to fix this?
t.column :metric_type, :assessorial_metric_type
Related
I need to join two very large tables from a single database in Rails. To reduce the amount of database calls, I want to use the .includes method. However, when I use this on my query I get the following error:
undefined method `first' for nil:NilClass on <% table_data.each do |d| %>
I can't for the life of my understand where this is coming from and how to fix it.
My code:
class Planning < ApplicationRecord
has_many :timeline, :foreign_key => "pcnrtoev"
end
class Timeline < ApplicationRecord
belongs_to :Planning
end
class OverviewController < ApplicationController
def index
#table_data = Planning.select(:pcnrtoev).includes(:timeline)
end
end
index.html.erb
<%= render partial: 'datatable', locals: {table_data: #table_data} %>
_datatable.html.erb
***
<% table_data.each do |d| %>
-do things-
<% end %>
****
Edit
If I change my initial query to
#table_data = Planning.select(:pcnrtoev).includes(:timeline).limit(50)
it seems to work. I still can't get to the data however, as it throws up this:
undefined method `telco_code_in' for #<Timeline::ActiveRecord_Associations_CollectionProxy:0x00007f4880c13638>
at
<% table_data.each do |d| %>
<%=if d.timeline.any?
>> telco_code_in = d.timeline.telco_code_in
end %>
<%end%>
Edit
It seems there is something wrong with the information I get from the database, rather than from the query itself. If I limit the output to 5000, everything is fine. If I limit the output to 10.000, I get the "No first method on .each"-error. Could this be because the Planning table can have one or more rows in the Timeline table?
Planning schema
create_table "planning", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "pcnrtoev", null: false
t.string "postcode", null: false
t.string "huisnr", null: false
t.string "toev"
t.index ["huisnr"], name: "huisnr"
t.index ["id"], name: "id"
t.index ["pcnrtoev"], name: "pcnrtoev"
t.index ["pcnrtoev"], name: "pcnrtoev_unique", unique: true
t.index ["postcode"], name: "postcode"
t.index ["toev"], name: "toev"
end
The Timeline table is a view instead of a table, so I don't have an actual schema for that. I scraped the code of everything that could cause the error, so this is my complete code for now.
Also, this is a pre-existing database, maybe that's useful information?
It is hard to give you right code without schema but I will do my best to explaining your mistake. So when you write
Planning.select(:pcnrtoev)
you are basically saying to database. Hey give me all pcnrtoev columns from planing table. If you paste this code in console you will se something like this
<Planning id: nil, pcnrtoev: INT>,
<Planning id: nil, pcnrtoev: INT2>...
So your database returns you only pcnrtoev columns and all other columns are nill.(Including columns from timeline table).
I hope you see what went wrong.
If you still have problem with writing the query, give me schema of Planing and Timeline table.
Using the Postgres database, added a text field staff_ids to branches table:
add_column :branches, :staff_ids, :text
In controller added this field to branch_params list:
:staff_ids => []
Data has been saved in this column like ["","32","52"]. When querying this field I got an error saying staff_ids should be an array
Branch.where("? = ANY(staff_ids)", '20')
ActiveRecord::StatementInvalid: PG::WrongObjectType: ERROR: op ANY/ALL (array) requires array on right side
Actually, I forgot to add array: true option in the migration when adding staff_ids field.
Now added another migration to change this column and tried to add array: true option:
change_column :branches, :staff_ids, :text, array: true
But the migration failed with an error:
PG::DatatypeMismatch: ERROR: column "staff_ids" cannot be cast automatically to type text[]
Now either I want to update the where clause so that it filters the branches based on staff_ids without adding the array: true or fix the migration mentioned above.
Any suggestion / idea ?
You can add the following in your migration,
def up
change_column :branches, :staff_ids, :text, array: true, default: [], using: "(string_to_array(staff_ids, ','))"
end
def down
change_column :branches, :staff_ids, :text, array: false, default: nil, using: "(array_to_string(staff_ids, ','))"
end
Defining up and down methods will help to reverse your migration at any time, if the change to an array was not required.
If I save a hash to the DB
hash_value = {"1"=>"val1", "2"=>"val2", "3"=>"val3", "4"=>"val4"}
#page.update(hash: hash_value)
Then try and loop through each key of the hash on the page page
hash = #page.hash
<%= hash.each do |key, value| %>
<%= value %>
<% end %>
I get the error undefined method 'each' for #<String:0x007fdda1d8b568>. This error made me realise it is saved saved as a string to the DB.
How do I make it save as a hash so when I pull it rom the DB it is in a hash not a string? Doing some research I found serialize but I cant make out how to use it properly. Is it used to change the DB table to have all values saved in that table be hashes? If so what is added in the migration file to do that?
create_table :pages do |t|
t.timestamps null: false
t.text :title
t.text :content_top
t.text :content_bottom
t.text :hash
t.timestamps null: false
end
Just confused as to how saving a hash to the DB and calling it as a hash is accomplished.
The column type for :hash on :pages table is text, which is the correct column type to use when you wish for a column to store a hash. You must now also indicate on the Page model that you wish to serialize this column. Something like this:
class Page < ActiveRecord::Base
serialize :hash
Then you can attempt to test your new setup like this:
#page = Page.new
#page.hash = {"1"=>"val1", "2"=>"val2", "3"=>"val3", "4"=>"val4"}
#page.save
You can use :json datatype, available in latest postgres 9.3 version onwards, it would be easy to save hash.
you should use serialize :hash to the model and then use it while save into the database.
I have to create a migration to do a db level validation. The migration:
class DataBaseLevelValidation < ActiveRecord::Migration
def change
add_index :benefits_business_changes, [:benefit_id, :business_change_id], :unique => true
end
end
The problem I have is that when I try to run rake db:migration I have this error:
Index name 'index_benefits_business_changes_on_benefit_id_and_business_change_id' on table 'benefits_business_changes' is too long;
the limit is 62 characters/Users/mariocardoso/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.5/lib/active_record/connection_adapters/abstract/schema_statements.rb:797:in `add_index_options'
But if I change the name to a shorter version I get this:
SQLite3::SQLException: no such table: main.benefits_businessc: CREATE UNIQUE INDEX "index_benefits_businessc_on_benefit_id_and_business_change_id" ON "benefits_businessc"
How can I overcome this problem?
The only ways I see, is to change the 'business_change' model to a shorter name (model, views, migration, ... everything).
There is any way to run this migration without having the error caused by the long name?
You can do
add_index :benefits_business_changes, [:benefit_id, :business_change_id], :unique => true, :name => "a_shorter_name"
A common choice is to use just the first few letters of each column.
I've seen we can avoid using a SEQUENCE on the object's ID by doing this:
create_table :table_name, :id => false do |t|
t.integer :id
t.timestamps
end
But, if my table is already created and I want to remove the "CREATE SEQUENCE table_name_id_seq" from the schema, how can I do this without dropping the table? If impossible it will be ok I guess but I did not want to loose my table content.
You'll have to use raw SQL to do this. Something like the following:
def up
ActiveRecord::Base.connection.execute "DROP SEQUENCE table_name_id_seq"
end
http://www.postgresql.org/docs/9.1/static/sql-dropsequence.html