I'm creating a table called Index. Here's the migration:
class CreateIndices < ActiveRecord::Migration
def change
create_table :indices, {:id => false} do |t|
t.string :name
t.float :returns, array: true, default: []
t.float :navs, array: true, default: []
t.float :sharpe
t.timestamps
end
execute "ALTER TABLE indices ADD PRIMARY KEY (name);"
end
end
That all works fine. I saw in another Stack Overflow question that I have to include the set_primary_key command in my model to get it to work, so I have the following in the index.rb
class Index < ActiveRecord::Base
set_primary_key :name
end
Besides these two files, I haven't changed anything from the default Rails scaffolding (the app was created with Postgres as the default database). When I go to localhost:3000/indices, I get the following error
undefined method `set_primary_key' for #<Class:0x37132e0>
If I comment out the set_primary_key line it loads the regular empty scaffold, but I assume this does not give me the primary key functionality that I want. What am I doing wrong?
If you're using rails 3.2 or higher, the set_primary_key method was depreciated, check out the Rails 3.2 release notes - Section 8.1 and it suggests using an assignment method instead like self.primary_key=, just like you said you did in your comment
Exactly it's currently a class method :
http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/PrimaryKey/ClassMethods.html#method-i-primary_key-3D
Don't forget the adequate migration :
def up
create_table :books, {id: false, primary_key: :key_id} do |t|
t.timestamps
etc.
end
execute <<-SQL
ALTER TABLE books
ADD PRIMARY KEY (key_id)
SQL
end
def down
drop_table :books
end
If you want to use this new primary key in your generated routes (routes.rb) :
resources :books, only: [:show, :edit, :update], param: :key_id
Hope it helps !
Take care
Weird. As per documentation I would have expected
class Index < ActiveRecord::Base
set_primary_key "name"
end
to work. The only difference I can see is "name" string vs your :name symbol which shouldn't make any difference.
Update
Actually, bang up the top of that link is a deprecated message (sorry). Apparently it's now a class method so that explains the need for self.set_primary_key. Doh!
Related
I am pretty new to rails so this may be a dumb question, but I have spent hours debugging this seemingly simple error and gotten nowhere. In my database, I want each row to to store an array of numbers (in a variable called contributions). I read that the best way to do that was by adding the following code:
class Goal < ActiveRecord::Base
#...
serialize :contributions, Array
#...
end
The attribute is also in goal.rb
ActiveRecord::Schema.define(version: 20150711171452) do
create_table "goals", force: :cascade do |t|
#...
t.decimal "contributions"
#...
end
end
I added it via this migration:
class AddContributorsToGoals < ActiveRecord::Migration
def change
add_column :goals, :contributors, :string
add_column :goals, :contributions, :decimal
end
end
The only problem is that whenever I try to access this attribute, I always get errors stating that it is of type BigDecimal. Rails thinks that this is a single number, but I want it to be a list of numbers. Any ideas as to what I could be doing wrong?
One example of a problem I get is that when this executes:
#goal.contributions << #goal.lastUpdateAmount
but I get this error
undefined method `<<' for #<BigDecimal:7f95e082ab18,'-0.0',9(9)>
I followed identical steps with an array of strings and that was serialized properly. I just don't know what's going on with this one.
Please change data type decimal to text
class AddContributorsToGoals < ActiveRecord::Migration
def change
add_column :goals, :contributions, :text
end
end
I just upgrade my app to rails 4.1.0.beta1
I have a class
class User < ActiveRecord::Base
enum usertype: { :employee => 10, :boss => 30, :manager => 40, :admin => 50 }
}
All the enum feature works well like user.boss? # ture
But when I try to get all user types by
User.usertypes
I got a undefined method for "usertypes"
Any helps?
This is the link the I learn from http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
Edit:
migration
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :password_digest
t.string :remember_token
t.boolean :is_locked
t.integer :usertype, default: 10
t.timestamp :last_login_at
t.timestamps
end
end
end
Have you created the proper migrations?
Enum attributes are values which map to integers in the database, but can be queried by name.
So you'll need a migration which adds an integer column with the name 'usertype' to the Users table. Have you done that?
EDIT 1:
Okay, just tested it out and the class method to get the mapping doesn't work with Rails 4.1.0.beta1, but does work with edge Rails. So hopefully that gets pulled into the next beta release...
EDIT 2:
Also, check out this commit which demonstrates the way you'd access the enum mapping in Rails 4.1.0.beta1 using a constant instead of a class method. So in your case you'd use User::USERTYPE to access your mapping.
Spent the past hour running migrate on heroku wondering why the following migrate doesn't set the primary key from id to what I want it to be:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products, :primary_key => :product_id do |t|
t.string :name
end
end
end
Then I figured there might be something wrong with the way I'm passing in the arguments so I changed it to
class CreateProducts < ActiveRecord::Migration
def change
create_table :products, {:primary_key => :product_id} do |t|
t.string :name
end
end
end
And all of a sudden Rails wasn't trying to look for the id column anymore when performing joins.
This might be a little vague but why do the braces matter? I was under the impression that trailing named parameters passed into a method are automatically treated as a hash as of Ruby 2.0.0 (during deployment, it says I was using ruby 2.0.0)
(I'm assuming create_table ... is a method call)
I'm reading Rails 3 in Action and following the commands verbatim. However, when I run the commands
rails new things_i_bought
cd things_i_bought
bundle install
rails generate scaffold purchase name:string cost:float
The book says I should get this code:
class CreatePurchases < ActiveRecord::Migration
def self.up #not created in my code
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down # not created in my code
drop_table :purchases
end
end
I get this code instead:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
Why are the class methods up and down not being created for me? I'm using
rails 3.1.1 and ruby 1.9.2.
thanks for reading my book!
As JacobM and dbalatero have already explained, this is a new feature in Rails 3.1. This particular feature was added by Aaron Patterson as a way to simplify the migration syntax. In earlier versions of Rails, you would have to do as the book shows:
class CreatePurchases < ActiveRecord::Migration
def self.up
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down
drop_table :purchases
end
end
But that's kind of repeating yourself. Aaron created a migration syntax that looks good and is simpler, calling only the methods necessary for migrating forward, but also allowing the migrations backwards (known as a "rollback") too. The same migration written with the Rails 3.1 syntax is this:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
So when this migration runs "forwards", Rails will create the purchases table with the fields. When you roll it back (or run it "backwards") then Rails will know to drop the table.
This syntax isn't entirely perfect however, and you'll run into problems with methods such as change_column. When that happens, it's best to stick with defining both the def up and def down methods in the migrations:
class CreatePurchases < ActiveRecord::Migration
def up
change_column :purchases, :cost, :integer
end
def down
change_column :purchases, :cost, :float
end
end
That's because in this example Rails won't know how to switch it back to the previous type. I hope this explains it better!
This is a new feature in Rails 3.1. For changes that Rails can figure out how to reverse, such as creating a table, you simply create a "change" method with the code that would have gone in "up", and it figures out how to do "down" on it's own.
You can also define "up" and "down" methods yourself -- for some changes (such as dropping a column) Rails won't be able to figure it out -- but the syntax is a bit different; it's not just def up instead of def self.up (they're now instance methods instead of class methods).
I believe in the new Rails 3.1, the database migration methods are self-aware about how to run an up/down migration.
Therefore, if you define a def change method, it will try to use those self-aware methods: in this case, create_table knows to do DROP TABLE in a down context, and CREATE TABLE in an up context.
If you want the old style, you can probably keep using it and define your own self.down and self.up methods as the book describes.
Edit: here's a link to the blog post on this, called "Reversible Migrations": http://www.edgerails.info/articles/what-s-new-in-edge-rails/2011/05/06/reversible-migrations/index.html
I created a simple example as a sanity check and still can not seem to destroy an item on either side of a has_and_belongs_to_many relationship in rails.
Whenever I try to delete an object from either table, I get the dreaded NameError / "uninitialized constant" error message.
To demonstrate, I created a sample rails app with a Boy class and Dog class. I used the basic scaffold for each and created a linking table called boys_dogs. I then added a simple before_save routine to create a new 'dog' any time a boy was created and establish a relationship, just to get things setup easily.
dog.rb
class Dog < ActiveRecord::Base
has_and_belongs_to_many :Boys
end
boy.rb
class Boy < ActiveRecord::Base
has_and_belongs_to_many :Dogs
def before_save
self.Dogs.build( :name => "Rover" )
end
end
schema.rb
ActiveRecord::Schema.define(:version => 20100118034401) do
create_table "boys", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "boys_dogs", :id => false, :force => true do |t|
t.integer "boy_id"
t.integer "dog_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "dogs", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end
I've seen lots of posts here and elsewhere about similar problems, but the solutions are normally using belongs_to and the plural/singular class names being confused. I don't think that is the case here, but I tried switching the habtm statement to use the singular name just to see if it helped (with no luck). I seem to be missing something simple here.
The actual error message is:
NameError in BoysController#destroy
uninitialized constant Boy::Dogs
The trace looks like:
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:105:in const_missing'
(eval):3:indestroy_without_callbacks'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/callbacks.rb:337:in destroy_without_transactions'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:229:insend'
...
Thanks.
I don't see your destroy callback, but I do see a couple of problems. First, your associations need to be lowercase. So dog.rb should be:
class Dog < ActiveRecord::Base
has_and_belongs_to_many :boys
end
and boy.rb should be:
class Boy < ActiveRecord::Base
has_and_belongs_to_many :dogs
def before_save
self.dogs.build( :name => "Rover" )
end
end
Second, I believe you want to use self.dogs.create instead of self.dogs.build above, since build won't actually save the new dog object.
The accepted answer here solved my problem, only to create another one.
Here are my model objects:
class Complex < ActiveRecord::Base
set_table_name "Complexes"
set_primary_key "ComplexID"
has_and_belongs_to_many :amenities
end
class Amenity < ActiveRecord::Base
set_table_name "Amenities"
set_primary_key "AmenityID"
end
Rails uses the name of the association as the table name when creating the select query. My application runs on Unix against a legacy MySQL database and my table names are case-sensitive and don't conform to Rails conventions. Whenever my app actually tried to load the association, I would get an exception that MySQL couldn't find table amenities:
SELECT * FROM `amenities`
INNER JOIN `ComplexAmenities` ON `amenities`.AmenityID = `ComplexAmenities`.AmenityID
WHERE (`ComplexAmenities`.ComplexID = 147 )
I searched and searched and could not find a way to tell Rails to use the correct case for the table name. Out of desperation, I tried passing a :table_name option to habtm and it worked. My new Complex model looks like this:
class Complex < ActiveRecord::Base
set_table_name "Complexes"
set_primary_key "ComplexID"
has_and_belongs_to_many :amenities, :table_name => 'Amenities'
end
This works under Rails 2.3.5.
This option is not mentioned in the Ruby on Rails docs.