Mongoid and ActiveRecord generators - ruby-on-rails-3

I have both ActiveRecord (MySQL) and Mongoid in my Rails 3.1 application. Everything is fine, excepts all generators uses mongoid to generate models. This way, when i:
rails g model user
i receive mongoid-like model, but i need ActiveRecord structure and migrations.
How can i switch back to AR?

Mongoid overrides the model generator, but you can switch it back.
In config/application.rb you can either add a line if you've already got a block similar to this:
config.generators do |g|
g.template_engine :haml
...
g.orm :active_record
end
Or just simply add the entire config line directly to the file
config.generators.orm :active_record
You can also pass :migrations => false if you want to turn off migrations

Related

Migrating from Rails 2.3.11 to Rails 3.0.11: Now unable to use find with a collection of AR records

I'm In the process of migrating from Rails 2.3.11 to Rails 3.1.3 and I am now on Rails 3.0.11 and sorting out all the issues that this brings.
The first one I can't solve is: in Rails 2.3.11, I could do the following and get the required records back
#event_type_time_units = TimeUnit.find(#event.event_type.time_units)
In Rails 3.0.11, I've tried using
#event_type_time_units = TimeUnit.find_with_ids(#event.event_type.time_units)
and
#event_type_time_units = TimeUnit.find_some(#event.event_type.time_units)
The code for both of those doesn't do anything magical and I expected them not to work.
Does anyone have a pointer for me, please.
Thank you
edit: the error I get is TypeError in MeetingsController#create
Cannot visit TimeUnit
Rails 3 uses Arel aka relational algebra to fetch associations. Assuming your EventType model has an association to has_many :time_units, you can just do the following:
#event_type_time_units = #event.event_type.time_units
Furthermore, you can optimize your queries using EventType as a join model (ish):
# app/models/event.rb
belongs_to :event_type
has_many :time_units, :through => :event_type
# app/models/event_type.rb
has_many :events
has_many :time_units
Now, you can query directly, saving a SQL call:
#event_time_units = #event.time_units
In short, there's no reason to do a find on an association. The association returns an "Array" of the records. (I use "Array" in quotes, because it's not really an array, but an ActiveRecord::Association which behaves much like an array)
Aside
I highly recommend just migrating to Rails 3.1.3. It's just as difficult to migrate from Rails 2 -> 3 as 3 => 3.1. Save yourself the middle headache. In fact, given the legacy of your application, I recommend the following:
Create a new, empty Rails 3.1.3 application
Copy all your models, views, controllers, and libs to this new application
Search your existing projects for gems -> add them to your Gemfile
Review everything in config/*. This is where a LOT of changes have take place. If you have application-specific code in your existing application, port it over to the new one. Otherwise, leave it alone.

Generating a migration from model

I am a beginner in Ruby on Rails and following the below article:-
http://guides.rubyonrails.org/migrations.html
If I need to generate a migration and a model, I can use, for example :-
$ rails generate model Product name:string description:text
and that would create :-
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
However, If I have a bigger model (with many properties). I don't want to put all the properties in the "rails generate" command. Can I hand code the model first and then generate the migration from that model file?
Sorry for asking so stupid question. I am just trying to understand.
Generate command is not must to do thing. It's just a script which helps you to automate some job. What exactly this command has done you can see in console after running generate command. It looks like this:
rails generate scaffold User name:string email:string
invoke active_record
create
db/migrate/20100615004000_create_users.rb
create
app/models/user.rb
invoke
test_unit
create
test/unit/user_test.rb
create
test/fixtures/users.yml
route resources :users
invoke scaffold_controller
create
app/controllers/users_controller.rb
invoke
erb
create
app/views/users
create
app/views/users/index.html.erb
create
app/views/users/edit.html.erb
create
app/views/users/show.html.erb
create
app/views/users/new.html.erb
create
app/views/users/_form.html.erb
invoke
test_unit
create
test/functional/users_controller_test.rb
invoke
helper
create
app/helpers/users_helper.rb
invoke
test_unit
create
test/unit/helpers/users_helper_test.rb
invoke stylesheets
converted by Web2PDFConvert.com
create
public/stylesheets/scaffold.css
You can actually create/modify all files by your hand. But the benefit of using generate is that it automatically invokes all necessary plugins and etc to generate all required files.
That's why it's recommended to use generate command even for very complicated models, controllers and etc.
So in your case I would suggest to divide the building the model in several steps. It could be like this:
rails generate model Product name:string description:text
rails generate migration AddPriceToProducts price:integer
rails generate migration AddDiscountToProducts discount:integer
and so on
Every step you could rollback in case if you made some mistake and it helps you to not harm
your database.
You can hand-code the migration. The model's attributes are read directly from the database... so if you add t.string :name to the migration file, and then run rake db:migrate, that column will be added to the table, therefore making it available as an attribute on your model.

rails3-amf - to_amf method not found on ActiveRecord objects

I am using the rails3-amf gem by warhammerkid in my Rails 3 / Flex 4 project.
AFAIK, I have correctly followed the "Getting Started" instructions from the GitHub page.
I have added the gem lines to my Gemfile.
I have installed the gems using bundle install.
From my Flex application, I will be making the RemoteObject call to the index action in the ManageMySchool::GradesController file. This is the code in the app/controllers/manage_my_school/grades_controller.rb file:
class ManageMySchool::GradesController < ApplicationController
respond_to :html, :amf
def index
#grade = Grade.first
respond_with(#grade) do |format|
format.amf { render :amf => #grade.to_amf }
end
end
end
The name of the model which is to be serialized is called Grade in both the Rails project (app/models/Grade.rb) and the Flex project (Grade.as with a RemoteAlias set as Grade). In the config/application.rb file, I have done the class mapping this way:
config.rails3amf.class_mapping do |m|
m.map :as => 'Grade', :ruby => 'Grade'
end
And I have done a parameter mapping this way:
config.rails3amf.map_params :controller => 'ManageMySchool::GradesController', :action => 'index', :params => [:authenticity_token]
Problem
Now, when I run the server and make the RemoteObject call from Flex, I get a to_amf undefined method error for the Grade model.
If I change Grade.first to Grade.all, #grade would have an array of Grades. But the undefined method error message still mentions the Grade model. This means that the to_amf method is working for the Array class but not for the ActiveRecord model.
Why is this? What am I doing wrong?
Is there something I have to do to "enable" the rails3-amf gem for ActiveRecord models?
I would appreciate any insights. Thanks!
Update
#warhammerkid: Here is the output of Grade.ancestors as seen in rails console.
ree-1.8.7-2011.03 :006 > puts Grade.ancestors
Grade
ActiveRecord::Base
Paperclip::CallbackCompatability::Rails3::Running
Paperclip::CallbackCompatability::Rails3
Paperclip::Glue CanCan::ModelAdditions
Authlogic::ActsAsAuthentic::ValidationsScope
Authlogic::ActsAsAuthentic::SingleAccessToken
Authlogic::ActsAsAuthentic::SessionMaintenance
Authlogic::ActsAsAuthentic::RestfulAuthentication::InstanceMethods
Authlogic::ActsAsAuthentic::RestfulAuthentication
Authlogic::ActsAsAuthentic::PersistenceToken
Authlogic::ActsAsAuthentic::PerishableToken
Authlogic::ActsAsAuthentic::Password
Authlogic::ActsAsAuthentic::MagicColumns
Authlogic::ActsAsAuthentic::Login
Authlogic::ActsAsAuthentic::LoggedInStatus
Authlogic::ActsAsAuthentic::Email
Authlogic::ActsAsAuthentic::Base
ActiveRecord::Aggregations
ActiveRecord::Transactions
ActiveRecord::Reflection
ActiveRecord::Serialization
ActiveModel::Serializers::Xml
ActiveModel::Serializers::JSON
ActiveModel::Serialization
ActiveRecord::AutosaveAssociation
ActiveRecord::NestedAttributes
ActiveRecord::Associations
ActiveRecord::AssociationPreload
ActiveRecord::NamedScope
ActiveModel::Validations::Callbacks
ActiveRecord::Callbacks
ActiveModel::Observing
ActiveRecord::Timestamp
ActiveModel::MassAssignmentSecurity
ActiveRecord::AttributeMethods::Dirty
ActiveModel::Dirty
ActiveRecord::AttributeMethods::TimeZoneConversion
ActiveRecord::AttributeMethods::PrimaryKey
ActiveRecord::AttributeMethods::Read
ActiveRecord::AttributeMethods::Write
ActiveRecord::AttributeMethods::BeforeTypeCast
#<Module:0x1028356f0> ActiveRecord::AttributeMethods::Query
ActiveRecord::AttributeMethods
ActiveModel::AttributeMethods
ActiveRecord::Locking::Optimistic
ActiveRecord::Locking::Pessimistic
ActiveRecord::Validations
ActiveModel::Validations::HelperMethods
ActiveModel::Validations
ActiveSupport::Callbacks
ActiveModel::Conversion
ActiveRecord::Persistence Object
PP::ObjectMixin Base64::Deprecated
Base64
ActiveSupport::Dependencies::Loadable
Kernel
Note that only ActiveModel::Serialization is there. No mention of Rails3AMF.
Does this mean I have to do something special to load the Rails3AMF module for the ActiveRecord models?
I am using Rails 3.0.5 with the latest version of ree. The gems are all contained in a gemset managed using rvm.
Update 2
If I remove the to_amf in the render :amf line, then I get the following error:
Grade Load (0.3ms) SELECT `grades`.* FROM `grades` LIMIT 1
Completed 200 OK in 195ms (Views: 0.1ms | ActiveRecord: 0.8ms)
Sending back AMF
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.last):
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/_request_and_response.erb (2.8ms)
Rendered /Users/anjan/.rvm/gems/ree-1.8.7-2011.03#rb/gems/actionpack-3.0.5/lib/> > action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (13.6ms)
Started POST "/amf" for 127.0.0.1 at Fri Apr 15 17:03:34 +0530 2011
Sending back AMF
Update 3
If I manually add the line include Rails3AMF::Serialization at the top of the Grade.rb model file, then it all works. So, does this mean that I have to put this line in all my models?
I see that this is already being done in line numbers 40 - 42 in the lib/rails3-amf/serialization.rb file of the gem:
# Hook into any object that includes ActiveModel::Serialization
module ActiveModel::Serialization
include Rails3AMF::Serialization
end
Why isn't this working? Should I force-load the gem when my application initializes or something?
Thanks!
Update 4 - Solved by this workaround
Okay, I just ended up adding this code block in an initializer:
class ActiveRecord::Base
include Rails3AMF::Serialization
end
And it is working.
#warhammerkid - Thanks for the help.
Rails3AMF::Serialization, the module that adds the to_amf method, is included in ActiveModel::Serialization when Rails3-AMF loads. If it's somehow not being included even though the code is running and ActiveModel::Serialization is one of your model's ancestors, then the simplest solution is just to add "include Rails3AMF::Serialization" at the top of your model implementation. I've never tried gem sets before, but it might be an issue with them, as everything works correctly using Bundler.
As an aside, feel free to post a bug to https://github.com/warhammerkid/rails3-amf/issues.

Rails 3 namespacing requires model to be defined twice?

I'm pulling my hair out trying to understand namespacing in Rails 3. I've tried following a few different tutorials, and the only way I can get my models to work is if I define my model in both the base directory and my namespace directory.
If I only define the model in the namespace directory it expects it to define both Model and Namespace::Model, as below:
LoadError (Expected .../app/models/plugins/chat.rb to define Chat):
or
LoadError (Expected .../app/models/plugins/chat.rb to define Plugins::Chat):
I'm sure I'm missing something obvious, but I could really use a pointer in the right direction.
Here are the relevant excerpts.
/models/plugins/chat.rb
class Plugins::Chat
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
...
end
/controllers/plugins/chats_controller.rb
class Plugins::ChatsController < Plugins::ApplicationController
load_and_authorize_resource
...
end
/config/routes.rb
namespace :plugins do
resources :chats
end
/config/application.rb
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Edit
This is some kind of bad interaction with CanCan, the gem we're using for permissions. The line load_and_authorize_resource is somehow at fault. Will keep digging...
I noticed a reference to load_and_authorize_resource in your controller. This method is used by the CanCan gem to create an instance of your model and then test if the user has access to it. If you are using a namespaced model you will need to specify the class:
class Plugins::ChatsController < Plugins::ApplicationController
load_and_authorize_resource :class "Plugins::Chat"
...
end
It sounds like at some point you're referencing the Chat constant \by itself before it's loaded. Rails then tries to find that by looking at models/chat.rb, can't find it, and complains. Check your constant usage (the backtrace should tell you where it's being invoked from), and clean it up, and Rails should be less complain-y.

How do I generate specs for existing controllers?

I have several controllers already set up. Now I want to start writing spec tests for them. Is there a command that generates the spec files automatically? I know rails does this for new resources, but I don't know if it does it for existing controllers/models too.
rails g rspec:controller ControllerName
When it asks you to override the existing controller, type n.
There are two options. If you want an empty spec file, you could try with:
rails g rspec:controller ControllerName
Now, if you want a spec file with initial specs for a basic REST controller, try with:
rails g rspec:scaffold ControllerName
If you've configured rspec in application.rb:
config.generators do |g|
g.test_framework :rspec
end
then rails g controller things will work. Opt not to overwrite files as they're generated.
All a spec looks like when it's generated is the following:
require 'spec_helper'
describe ThingsController do
it "should be successful" do
get :index
response.should be_successful
end
end
I often create the specs manually, as it's rather trivial.