How to setup MongoMapper Observer - ruby-on-rails-3

I'm trying to create some mongo mapper observer.
I found a class exit for that : http://rubydoc.info/gems/danielharan-mongo_mapper/0.6.5/MongoMapper/Observer
The question is how to activate them.
I create an app/observers/admin_observer.rb
class AdminObserver < MongoMapper::Observer
observe :admin # my admin model
# call backs ...
end
The question now is how to active them ?
The active record way is :
module MyApp
class Application < Rails::Application
config.active_record.observers = :admin
# other config
end
end
But with MongoMapper no active_record. Quite naive, I tried config.mongo_mapper.observers = :admin, but their is no observers in mongo_mapper configuration ...
I dunno what to try else and my google research didn't give me a clue.

That appears to be a really old, un-maintained fork of MongoMapper--using a 2-year-old gem is asking for trouble.
If you find it's really better to use an observer rather than just implement the callbacks directly in your model, your best bet may be to fork MongoMapper and add the functionality you want (MM's code is pretty clean), or better yet make a gem that extends MongoMapper with an observer functionality.

Related

Rails, A method to be called only in production

I remember seeing this somewhere online but I know have trouble finding information about it. In Rails 3.1, I have a method at the beginning of a session controller, force_ssl, I only want it called in a production environment, how do I do that?
To clarify, the code looks something like this
class SessionsController < ApplicationController
force_ssl
end
I had a similar problem. force_ssl caused problems by testing with capybara and selenium. This here solved my problems and the tests are now running:
force_ssl if Rails.env.production?
I am using the line above in some Controllers. For example in the SessionController and UserController.
Rails.env.production? returns true if the current environment is 'production'. More generally, Rails.env.somestring? returns true if Rails.env == "somestring". From there you should be good.
** EDIT **
Well actually, there's an easier way to use ssl only in production. Check out this article

How to mock and stub active record before_create callback with factory_girl

I have an ActiveRecord Model, PricePackage. That has a before_create call back. This call back uses a 3rd party API to make a remote connection. I am using factory girl and would like to stub out this api so that when new factories are built during testing the remote calls are not made.
I am using Rspec for mocks and stubs. The problem i'm having is that the Rspec methods are not available within my factories.rb
model:
class PricePackage < ActiveRecord::Base
has_many :users
before_create :register_with_3rdparty
attr_accessible :price, :price_in_dollars, :price_in_cents, :title
def register_with_3rdparty
return true if self.price.nil?
begin
3rdPartyClass::Plan.create(
:amount => self.price_in_cents,
:interval => 'month',
:name => "#{::Rails.env} Item #{self.title}",
:currency => 'usd',
:id => self.title)
rescue Exception => ex
puts "stripe exception #{self.title} #{ex}, using existing price"
plan = 3rdPartyClass::Plan.retrieve(self.title)
self.price_in_cents = plan.amount
return true
end
end
factory:
#PricePackage
Factory.define :price_package do |f|
f.title "test_package"
f.price_in_cents "500"
f.max_domains "20"
f.max_users "4"
f.max_apps "10"
f.after_build do |pp|
#
#heres where would like to mock out the 3rd party response
#
3rd_party = mock()
3rd_party.stub!(:amount).price_in_cents
3rdPartyClass::Plan.stub!(:create).and_return(3rd_party)
end
end
I'm not sure how to get the rspec mock and stub helpers loaded into my factories.rb and this might not be the best way to handle this.
As the author of the VCR gem, you'd probably expect me to recommend it for cases like these. I do indeed recommend it for testing HTTP-dependent code, but I think there's an underlying problem with your design. Don't forget that TDD (test-driven development) is meant to be a design discipline, and when you find it painful to easily test something, that's telling you something about your design. Listen to your tests' pain!
In this case, I think your model has no business making the 3rd party API call. It's a pretty significant violation of the single responsibility principle. Models should be responsible for the validation and persistence of some data, but this is definitely beyond that.
Instead, I would recommend you move the 3rd party API call into an observer. Pat Maddox has a great blog post discussing how observers can (and should) be used to loosely couple things without violating the SRP (single responsibility principle), and how that makes testing, much, much easier, and also improves your design.
Once you've moved that into an observer, it's easy enough to disable the observer in your unit tests (except for the specific tests for that observer), but keep it enabled in production and in your integration tests. You can use Pat's no-peeping-toms plugin to help with this, or, if you're on rails 3.1, you should check out the new functionality built in to ActiveModel that allows you to easily enable/disable observers.
Checkout the VCR gem (https://www.relishapp.com/myronmarston/vcr). It will record your test suite's HTTP interactions and play them back for you. Removing any requirement to actually make HTTP connections to 3rd party API's. I've found this to be a much simpler approach than mocking the interaction out manually. Here's an example using a Foursquare library.
VCR.config do |c|
c.cassette_library_dir = 'test/cassettes'
c.stub_with :faraday
end
describe Checkin do
it 'must check you in to a location' do
VCR.use_cassette('foursquare_checkin') do
Skittles.checkin('abcd1234') # Doesn't actually make any HTTP calls.
# Just plays back the foursquare_checkin VCR
# cassette.
end
end
end
Although I can see the appeal in terms of encapsulation, the 3rd party stubbing doesn't have to happen (and in some ways perhaps shouldn't happen) within your factory.
Instead of encapsulating it in the factory you can simply define it at the start of your RSpec tests. Doing this also ensures that the assumptions of your tests are clear and stated at the start (which can be very helpful when debugging)
Before any tests that use PricePlan, setup the desired response and then return it from the 3rd party .create method:
before(:all) do
3rd_party = mock('ThirdParty')
3rdPartyClass::Plan.stub(:create).and_return(true)
end
This should allow you to call the method but will head off the remote call.
*It looks like your 3rd Party stub has some dependencies on the original object (:price_in_cents) however without knowing more about the exact dependency I can't guess what would be the appropriate stubbing (or if any is necessary)*
FactoryGirl can stub out an object's attributes, maybe that can help you:
# Returns an object with all defined attributes stubbed out
stub = FactoryGirl.build_stubbed(:user)
You can find more info in FactoryGirl's rdocs
I had the same exact issue. Observer discussion aside (it might be the right approach), here is what worked for me (it's a start and can/should be improved upon):
add a file 3rdparty.rb to spec/support with these contents:
RSpec.configure do |config|
config.before do
stub(3rdPartyClass::Plan).create do
[add stuff here]
end
end
end
And make sure that your spec_helper.rb has this:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Well, first, you're right that 'mock and stub' are not the language of Factory Girl
Guessing at your model relationships, I think you'll want to build another object factory, set its properties, and then associate them.
#PricePackage
Factory.define :price_package do |f|
f.title "test_package"
f.price_in_cents "500"
f.max_domains "20"
f.max_users "4"
f.max_apps "10"
f.after_build do |pp|
f.3rdClass { Factory(:3rd_party) }
end
Factory.define :3rd_party do |tp|
tp.price_in_cents = 1000
end
Hopefully I didn't mangle the relationship illegibly.

Using memcache in a Rails 3 app

Do you have to add code to your Rails app to use memcache? I've added config.cache_store = :dalli_store to my production environment and Rails.cache.write('color', 'red') works.
I haven't made any modifications to my models, views, or controllers. When I create and save an object, for example
user = User.new
user.name = 'John Doe'
user.email = 'john#doe.com'
user.save
it is going straight to the database and not going to memcache. I was hoping activerecord would use memcache automatically if configured for it. Is that not the case? Any good articles on rewriting your models to use Rails.cache (or should this be something done in the controller)?
config.cache_store is only going to be used for configuring the store used in writing and retrieving cache. This is completely separate from your model data storage.
http://guides.rubyonrails.org/caching_with_rails.html
Are you trying to substitute an ActiveRecord database like MySQL with memcached? Writing to memcached when you create a new record, instead of writing to a database?
UPDATE BASED ON YOUR COMMENT
cache_money is doing the write_through using activerecord callbacks.
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Look at the line 15-17 and you can see where they call the after callbacks:
https://github.com/nkallen/cache-money/blob/master/lib/cash/write_through.rb
You could accomplish what you need in the same manner. Just code a custom method and make it available to your models. Then call the method with after_create, after_update, after_destroy in the model. If you want to make it happen to all models, you could probably do this in an initializer:
#UNTESTED, but should be close
ActiveRecord::Base.descendants.each do |model|
model.class_eval do
after_create :your_cache_method
#... other callbacks
end
end
You could then code a module with your_cache_method in it and include it in ActiveRecord::Base, so it would be available to all models

Rails3 Devise custom routing for confirmable module

I am trying to route a user to a custom welcome page after they confirm their account via devise's confirmable. The custom page is located at /districts/setup/, reachable by districts_setup_path.
To do this I added the custom route,
devise_for :users, :controllers => { :registrations => 'registrations', :confirmations => 'confirmations' }
and created my own controller. Then I had to overload the confirmations_controller.rb and now have:
(app/controllers/confirmations_controller.rb)
class ConfirmationsController | Devise::ConfirmationsController
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message(:notice, :confirmed) if is_navigational_format?
sign_in(resource_name, resource)
redirect_to districts_setup_path
else
render_with_scope :new
# not:
# respond_with_navigational(resource.errors, :status => :unprocessable_entity){
end
end
end
This works well, but I am nervous that I am not doing this in the mostideal and robust way. In particular, I just deleted the respond_with_navigational( ... ) lines which I really don't understand.
I am hoping to write this all up in a how-to for the Devise wiki, and am just looking for feedback being fairly new to rails and even newer to Devise/engines/warden.
Taking a look on Devise's ConfirmationsController you can spot the protected method after_confirmation_path_for(resource_name, resource). Overriding it (rather than the whole action) will produce the same results with less effort.
Generally speaking, there is no problem with overriding Devise's controller since they represent the default behavior which doesn't always suit the application needs. That being said you must take a few things before overriding Devise's code:
Devise is not just another component of the system - it handles user authentication, which is a very sensitive issue. Make sure you don't break anything important before you commit it. You can do so by forking the Devise project from github, making your changes, and running the tests.
As you make changes to devise and override its code, it will become harder to upgrade to newer version, which might be incompatible with your changes.
If you do decide to make a change, look for the smallest change possible to achieve your goal. In most of the cases Devise's team has already foreseen the need for customization in certain places and left methods (like the one above) which are dedicated just for it. Again, going over the file's code on Devise's GitHub would give you a good idea as for what is the best way to customize its behavior to your needs.

Rails 3 - extend ActionController

I am trying to implement logic captcha in my app. I have scaffolded simple TextCaptcha to store question and answer in DB.
Currently I have this in initializers/text_captcha.rb
require 'text_captcha'
ActionController::Base.send(:include, TextCaptcha)
This in "lib/text_captcha.rb":
module TextCaptcha
def self.included(base)
base.send(:include, InstanceMethods)
end
module InstanceMethods
def require_text_captcha
#captcha = "hello!"
end
end
end
So in comments controller I have this to have access to #captcha in view
before_filter :require_text_captcha
The bad thing is I have to restart webrick every time I make changes - so I think I'm doing this in a wrong way? I could get rid of initializer and just require "text_captcha" where I need... Or is there a way to do this in "models/text_capctha.rb" which I was trying to do in the beginning but could figure out.
Since ApplicationController in a Rails app extends from ActionController::Base, can you do:
require 'text_captcha'
class ApplicationController < ActionController::Base
include TextCaptcha
end
in app/controllers/application_controller.rb?
If TextCaptcha is getting blown away when Rails reloads your models the fix is to use to_prepare instead of an initializer to load it. See the following resources for more information:
Official Docs: http://api.rubyonrails.org/classes/ActionDispatch/Callbacks.html#method-c-to_prepare
Short Blog Post: http://www.cowboycoded.com/2011/01/28/reloading-rails-3-engine-initializers-in-development/