Using Datamapper with existing rails application - ruby-on-rails

I have an existing Rails 3 application using ActiveRecord, and I want to switch to Datamapper. The instructions given in the dm-rails page only talk about creating a new application. Does anyone know how to throw away all activerecord dependancies and migrate to datamapper?
Thanks!

It's realtively straightforward, but there are a couple of things you need to do.
In your Gemfile, remove "rails" and instead require the following.
gem 'activesupport', RAILS_VERSION, :require => 'active_support'
gem 'actionpack', RAILS_VERSION, :require => 'action_pack'
gem 'actionmailer', RAILS_VERSION, :require => 'action_mailer'
gem 'railties', RAILS_VERSION, :require => 'rails'
Where RAILS_VERSION is the version of Rails you want to use (e.g. ~> 3.1). This is basically all of rails except ActiveRecord.
At the top of config/application.rb, remove the require for rails (I forget what the original require looks like) and replace it with specific requires for the railties you need.
require "action_controller/railtie"
require "action_mailer/railtie"
I think the only other one is a Test::Unit railtie, but we're not using Test::Unit, so we don't include it.
Finally, if you want to use the identity map (I suggest you do, but it's not needed), place in your ApplicationController's class body:
use Rails::DataMapper::Middleware::IdentityMap
That should be everything; the rest is just configuring your database.yml according to the README (it's pretty much cross-compatible with a standard rails one anyway).
For reference, take a look at what the generators does:
-zsh$ curl http://datamapper.org/templates/rails.rb
apply 'http://datamapper.org/templates/rails/gemfile.rb'
apply 'http://datamapper.org/templates/rails/application.rb'
If you look at the contents of those two files you'll see the extra stuff you'd get if you had used the generator.

Related

Use two gems in same namespace in Rails

I have an app that uses the LinkedIn gem but I need to move towards using the LinkedIn OAuth2 implementation which comes in a different gem.
I need to support the requests on oAuth1 in the initial gem for existing users, but I need to support OAuth2 for new users going forwards.
The problem is, both of these gems use the LinkedIn namespace for their module names, and depending on what order I include them in my Gemfile, one clobbers the other.
I tried adding require: false to the gemfile like so:
gem 'linkedin', require: false
gem 'linkedin-oauth2', require: false
But weirdly enough when I go to my console, the first one is still being required, where as the second one is not:
irb(main):001:0> require 'linkedin'
=> false
irb(main):002:0> require 'linkedin-oauth2'
=> true
Is this something to do with how require works? Is it possible to load just one of these gems each in separate lib files without clobbering each other?
EDIT
I figured out that I was requiring the linkedin in one of my spec files, which was causing it to be autoloaded, but that did not still fix the issue of things being clobbered.
When I have both gems installed and I run:
irb(main):001:0> require 'linkedin'
=> true
irb(main):002:0> ::LinkedIn::Client.new
NameError: uninitialized constant Api::QueryHelpers
from /Users/me/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/linkedin-1.1.0/lib/linked_in/client.rb:8:in `<class:Client>'
irb(main):004:0> require 'linkedin-oauth2'
=> true
But if I uninstall linkedin-oauth2 from my gemfile it works just fine:
irb(main):002:0> require 'linkedin'
=> true
irb(main):004:0> ::LinkedIn::Client.new
=> #<LinkedIn::Client:0x007f9eef6d72a8 #consumer_token=nil, #consumer_secret=nil, #consumer_options={}>
Why is that, especially since linkedin-oauth2 is not being required in the first example, yet the error occurs. Could it be because of how they require supporting files in the linkedin gem? Seems still like it shouldn't affect it.
I wouldn't recommend doing this, since it could have some weird side effects such as if linkedin-oauth2 references itself with ::LinkedIn, but a method to redefine a ruby constant is shown in this answer.
I would change it a little bit to prevent renaming a constant warning... Object.send(:remove_const, :Stripe) instead of the Stripe = Module.new as shown in the answer. So, an example (not tested) would be:
require 'linkedin-oauth2'
LinkedInOauth2 = LinkedIn
Object.send(:remove_const, :LinkedIn)
require 'linkedin'

Rails bootstrap gem monkeypatching method not working

I'm using the excellent twitter-bootstrap-rails gem. There is a helper within that gem (NavbarHelper) which is used to generate Bootstrap navbars with a Ruby helper. I want to monkey patch the gem such that the dropdown lists won't have carets.
So, I looked into the source and found the relevant method here. All I have to do is override it. I created a new file in config/initializers called navbar.rb with the following content:
NavbarHelper.module_eval do
def name_and_caret(name)
"HELLO WORLD"
end
end
Presumably, all of the dropdown titles then should be rendered as "HELLO WORLD" in my app (as referenced by the gem source). However, this is not occurring, and the gem does not appear to be monkeypatched at all.
I tried placing puts NavbarHelper.methods - Object.methods in the initializers file, and there were no results, which makes me think that Rails is not loading the gem correctly before the initializers. I have also checked and verified that the gem is not using autoload for its helpers.
Edit
What may be complicating this is the fact that my Gemfile includes the gem in the following manner:
gem 'twitter-bootstrap-rails', git: 'git://github.com/seyhunak/twitter-bootstrap-rails.git', branch: 'bootstrap3'
I'm not sure if this specific versioning means the monkeypatching doesn't work.
Edit #2
It seems there is only one version of the gem on my system, so I don't think that's the issue. Also, I have tried placing require 'twitter-bootstrap-rails at the top of the initializers file, with no results.
The problem is that you patch the method on this module but the module already got included at this point. Try to define this in your application_helper.rb
def name_and_caret(name)
super("blub #{name}")
end

How do I autoload an external gem in Rails?

I recently externalized my rails models outside of my rails-app into a gem (models_gem).
When my rails project imports the models_gem, i have to do a: require 'model' , in order to use the model. How can I automatically import all the models that are in my models_gem ??
you can do it in Gemfile eg:
gem 'models_gem', require: 'models_gem'
or fix your gem and in lib/models_gem.rb
ActiveRecord::Base.send(:include, ModelsGem)
Thats depends how your gem is made.
When you require a gem, it requires lib/gem_name.rb. If you require all the models in that file, in theory they should be loaded in your application.

What's the best way to use yajl-ruby with my Rails project?

Rails 2.3.6 started using the fast new json library, yajl-ruby, "if available".
In the "JSON gem Compatibility API" section of the yajl-ruby readme it outlines a method to just drop in yajl-ruby inclusion and have the rest of the app seamlessly pick it up.
So, ideally, I'd like
Rails to use it
My gems to use it
My application code to use it
What's the easiest way to achieve this? My guess:
config.gem 'yajl-ruby', :lib => 'yajl/json_gem'
As the very first gem in environment.rb. Doing this doesn't result in any errors, but I'm not sure how to know if rails is picking it up for its own use.
Thanks!
John
I'd recommend using yajl-ruby's API directly instead of the JSON gem compatibility API mainly for the reason that the JSON gem's to_json method conflict with ActiveSupport and has had long-standing issues making them work together.
If you just do config.gem 'yajl-ruby', :lib => 'yajl' instead, you'll need to use Yajl::Parser and Yajl::Encoder directly to parse/encode objects. The advantage of this is you'll be certain there won't be any conflicts with method overrides and as such, be guaranteed your JSON encoding/parsing code will work as expected.
The disadvantage is if you're using any gems that use the JSON gem, they'll continue to do so but you're own code will use yajl-ruby.
If you wanted to, you could use your config.gem line, then in an initializer require 'yajl' so you'd have both API's loaded. The yajl/json_gem include will override anything that's using the JSON gem with yajl - to ensure this overrides those methods try to make sure require 'yajl/json_gem' happens last.
If you're using Rails 3, you can add this to an initializer:
ActionController::Renderers.add :json do |json, options|
json = Yajl.dump(json) unless json.respond_to?(:to_str)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
self.response_body = json
end
To make sure render :json => ... calls use yajl-ruby as well.
Sorry if this isn't really answering your question but I wanted to at least give the suggestion of using yajl-ruby's API directly :)

how can we include installed gem in controller in RoR?

I have installed gem successfully.But how can we use use in controller?
Look inside of config/environment.rb. Inside of the Rails::Initializer.run block you should see a commented-out note that describes using config.gem.
You want to add the gem that you need with that method, like this:
config.gem "foo"
There are other options that you might need, depending on what gem you are trying to use. Mention what it is, and I can be more specific.
Also be sure to read the docs for the gem method.
Add require 'gem' to top of controller or specific method.
Sample use of rubyzip gem for ex
def zip(data, filename)
require 'zip/zip'
require 'zip/zipfilesystem'
zipfile = "/tmp/rubyzip-#{rand 32768}"
Zip::ZipOutputStream::open(zipfile) do |io|
io.put_next_entry(filename)
io.write data
end
zippy = File.open(zipfile).read
File.delete(zipfile)
zippy
end

Resources