I have a Hash attribute in my model that uses Postgres hstore extention. The problem is that this attribute is converted to String by Rails4. This prevents me to make basic operations such as .each or .map to treat my hash attribute.
Using the Rails console, the Hash is not converted. Typing:
#device.data
#device.data.class
Gives in Rails console:
{"city"=>"London", "owner_name"=>"John"}
Hash
And in the application itself (using the navigator):
"\"city\"=>\"London\","\"owner_name\"=>\"John\"
String
Do you have any idea?
Update:
Here is the model:
class Device < ActiveRecord::Base
belongs_to :company
has_many :records
validates :name, presence: true
end
And the corresponding migration file:
class CreateDevices < ActiveRecord::Migration
def change
create_table :devices do |t|
t.string :name
t.hstore :data
t.integer :company_id
t.timestamps
end
add_index :devices, :name
end
end
Try deleting your tmp folder and restarting all your servers.
rm -rf tmp/*
Related
I have added iconfolio to my character model. Each character has_one :iconfolio.
character.rb
has_one :iconfolio, dependent: :destroy
accepts_nested_attributes_for :iconfolio
before_validation do
self.create_iconfolio unless iconfolio
end
Here is the migration file:
class CreateIconfolios < ActiveRecord::Migration
def change
create_table :iconfolios do |t|
t.integer :character_id
t.string :icon_url
t.timestamps null: false
end
add_index :iconfolios, :character_id
end
end
The iconfolio class:
iconfolio.rb
class Iconfolio < ActiveRecord::Base
belongs_to :character
validates :character_id, presence: true
before_create do
self.icon_url = '/assets/icon1.png'
end
end
Firstly, how do I ensure an iconfolio has been created for each character?
Secondly, how do I update all the rows in the character_id column? The character_id value is different for every iconfolio record. Updating the icon_url column can be done in the console:
Iconfolio.all.update_all(person_normal_icon_url: '/assets/icon1.png')
The easiest way to do this is to create a default template iconfolio and update_all character records as you did with Iconfolio. If your database isn't already large you can iterate through Character.all and assign them an iconfolio. Be advised this will instantiate an object per row and be much more time consuming than update_all. The benefit of instantiating them is it will not bypass your validations. Write a block in your console that iterates through each record and finds or creates an iconfolio per character like:
Character.all.find_each do |char|
if char.iconfolio.blank?
Iconfolio.create(character_id: char.id, whatever_other_params: put_here)
end
end
Then make an after_create in your Character model that creates and assigns an iconfolio for future new characters. Something like:
after_create :make_an_iconfolio
def make_an_iconfolio
Iconfolio.create(character_id: self.id, other params here)
end
As a sidenote, the Rails way to add a relationship in your create_table migration is:
def change
create_table :iconfolios do |t|
t.belongs_to :character, index: true
This just makes it more clear to you and others that it's a relationship and saves an extra line of code from indexing.
I recently added new columns to my database (sqlite) for Media and it shows that the columns are inserted, but the new columns will not update on Medium.new
My original database:
class CreateMedia < ActiveRecord::Migration
def change
create_table :media do |t|
t.string :name
t.string :location
t.timestamps
end
end
end
These columns update on Media.new
class AddMetaToMedia < ActiveRecord::Migration
def change
add_column :media, :ext, :string
add_column :media, :l_mod, :string
add_column :media, :d_create, :string
end
end
and I am calling
Medium.new(name: f, location: str, ext: ex)
ext will not update to ex = File.extname(f), which I know has a value through print statements/console. Am I calling Medium.new wrong? Why is it updating name and location but not the new columns?
edit: Here is my model, I've tried with and without attr_accessible/attr_accesor
class Medium < ActiveRecord::Base
attr_accessor :ext, :d_create, :l_mod
end
Mostly for those who find this later...may also need to whitelist new params in interested controllers
attr_accessor :ext, :d_create, :l_mod remove this line from your model and try again.
Now you have these attributes in DB so Rails will do this job automatically
Please help with ActiveRecord testing. Trying my first Rails 3.1.0 project. There I have model named "Account", described like:
migration.rb:
def self.up
create_table :accounts do |t|
t.string :name
t.integer :type
t.references :user
t.timestamps
end
add_index :accounts, :user_id
end
account_model.rb
class Account < ActiveRecord::Base
belongs_to :user
validates_length_of :name, :within => 15..255
validates_numericality_of :type
end
And if i'm making in Rspec :
account = Account.new(:type => 1)
account.type.should == 1
I've got test result:
Failure/Error: account.type.should == 1
expected: 1
got: nil (using ==)
I tried Account creation in console, and every time i'm assigning any integer value as 'type', i got 'nil'. Not assigned value. What I'm making wrong?
'type' is a protected attribute in rails, because .type is a ruby method. Hence you can't mass assign it. Rename the attribute (eg :account_type) & everything should work fine.
I've been trying to setup a Single Table Inheritance model in Rails 3 in which the parent class also contains a has_many relationship. Unfortunately I can't get it to work. Here are three classes as an example:
class Article < ActiveRecord::Base
has_many :paragraphs, :dependent => :destroy, :autosave => true
end
class Paragraph < ActiveRecord::Base
belongs_to :article
end
class SportsArticle < Article
end
And here's the migration that would be used to set this up:
class AddTables < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.string :type, :null => false # for STI
t.string :title, :null => false
t.timestamps
end
create_table :paragraphs do |t|
t.references :article, :null => false
t.timestamps
end
end
def self.down
drop_table :articles
drop_table :paragraphs
end
end
When I set it up this way and I try to create a new SportsArticle, say by doing the following:
SportsArticle.create(:title => "Go Giants")
I always get the following error:
"TypeError: can't convert String into Integer"
I have no idea how to fix this issue and have tried finding a solution online to no avail. Does anybody who has experience with STI models see anything wrong? Here's the link to the documentation on the create method if it will help in diagnosing the problem:
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-create
Try renaming :type to something else, like :article_type
eg:
t.string :article_type, :null => false # for STI
The error was being caused due to a naming collision. I was using a name for one of my models called "attributes" which was causing the problem. The hint that eventually diagnosed the problem came from the Rails Association Documentation.
I want to put some model level validation on the following table:
create_table :audios do |t|
t.integer :library_id, :null => false
t.string :file, :null => false, :limit => 2048
t.string :name, :limit => 512
t.timestamps
end
Does this mean, that my model, which (so far) looks like:
class Audio < ActiveRecord::Base
belongs_to :library
end
Has
class Audio < ActiveRecord::Base
validates_presence_of :library
...
or
class Audio < ActiveRecord::Base
validates_presence_of :library_id
...
?
To validate the presence of an association, use its name, without _id appended:
validates_presence_of :library
It will validate two things:
library_id is present
a Library with the given id exists
Using validates_presence_of :library_id will only give you the first validation of the two.
In addition to this, the version without _id will also correctly validate if both records are new (and therefore library_id is still unset).