Using memcache in a Rails 3 app - ruby-on-rails-3

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

Related

Is there a Rails convention for how to structure nested models using FactoryGirl?

There is a part of BDD that I am really confused about. I have all kinds of different request specs to test. With the following structure:
User has_many Products
Product has_many PriceLevels
PriceLevel has_many Prices
I am confused about how to go about setting up factories using FactoryGirl. I am familiar with the concept of associations and traits. I am familiar with the concepts of build and create. But I am unsure in what situations to use these.
The best way I can communicate what I am confused about is to give some examples.
I have a request spec to test User registration. I don't use a factory here for obvious reasons. This I understand.
I have a request spec to test a User creating new Products. I create a user factory. I assume I need to use create instead of build here, because the CRUD methods in the ProductsController do an AR find on the id that is passed via the URL. Correct me if I'm wrong here.
I have a request spec to test adding different PriceLevels for a Product. Here I am using two factories: User and Product.
I have a request spec to test adding different Prices for a User's Product's PriceLevel. Now I'm up to 3 factories: User, Product, PriceLevel.
Now what if Price has a has_and_belongs_to_many with something like Currency? The factories are getting out of hand.
I'd say by the time I get to PriceLevel then I want a single factory that will let me create the whole structure at once. And yet, I don't want to create whole structure every single time. Plus, these factories can be created from the bottom up or the top down.
Which way is better, bottom up or top down? Can I create DRY code that gives me options on a single factory or creating the whole shebang at once? Can I wrap after(:create) blocks within traits? Would I ever use build vs create in request specs?
Thanks very much for your attention!
First of all, build vs create in Request specs:
I commonly use build or build_stubbed in controller specs by stubbing Model.find to return the built instances. However, mocking in general should be avoided in Feature or Request specs, so go ahead andcreate things here.
Now as for the main problem:
This sounds like a perfect case for traits. In general, base factories should have only the attributes required to make a valid model. Traits can then be used to make handy "aliases" for common or verbose scenarios.
You can use before(:create) to build and assign related models. Rails will handle saving everything together when FG eventually calls save/create internally.
Example:
factory :user do
# ...
trait :with_products do
before(:create) do |user|
user.products = build_list(:product, 3)
end
end
trait :with_priced_products do
before(:create) do |user|
user.products = build_list(:product, 3, :with_prices)
end
end
end
factory :product do
# ...
trait :with_prices do
before(:create) do |product|
product.prices = build_list(:price, 3)
end
end
end
factory :price
If you wanted to customize how many products/prices are added at build-time, you can just add ignored attributes and use them via the 2-argument form of the before-hook.
ignore do
number_of_products 3
end
before(:create) do |user, evaluator|
user.products = build_list(product, evaluator.number_of_products)
end
If you wanted to be able to use these with_ traits in build or build_stubbed scenarios, you're going to have to duplicate the relevant hooks using the correct strategy in each case. There's currently no easy way to say "add some relations using the same strategy as the model", though that's a wishlist item for myself too.

How to setup MongoMapper Observer

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.

How to access current_user from a Rails Notification?

I'm building an audit trail that needs to know which user is currently making the request. My audit trail is built using ActiveSupport::Notifications to receive an even that needs to be audited.
What I would like to do is use an ActiveSupport::Concern to encapsulate the logic for my audit needs, so that I can easily add auditing to any model in my system.
In general this is easy to do. I even blogged about it a while back. However, I'm having a hard time figuring out how to get the current user that making the request to the web server, so that I can log who is making what changes in my audit trail.
I know there are a ton of questions about "how do I get current_user in my model" but I'm not asking about doing it in a model, so I'm hoping there is a better set of answers. Since my audit code is infrastructure related, I am hoping that there is some way I can tap into the current request that is being processed, or something else that would definitively tell me who is currently logged in / making the request.
I've read a lot of "answers" that say to use thread storage and put the current_user in there. I don't like this answer for many of the reasons that others don't - there is no guarantee that thread storage is safe. it could bleed across multiple requests if the server uses the same thread to process multiple requests, etc.
so... given that I am not trying to access current_user from my model, but rather from either an ActiveSupport::Concern or ActiveSupport::Notifications event subscription, are there any good options for me to know who the current user is?
Update
I'm using devise for authentication, which uses Warden on the back end. devise retrieves the current_user by calling request.env['warden'].authenticate(:scope => :user) (assuming i use a "User" model for authentication).
Is there a way for me to access the current request object from within my concern or notification subscription? Back in my .NET days, I would have been able to call HttpContext.Current.Request and all would be good. What's the equivalent in Rails?
Rails' ActionController::Instrumentation has explicit support for this, using append_info_to_payload.
Add a method to your ApplicationController:
def append_info_to_payload(payload)
super
payload[:current_user_id] = current_user.try(&:id)
end
now, when your observer is called back, the information will be in the event.payload:
ActiveSupport::Notifications.subscribe /process_action.action_controller/ do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
current_user_id = event.payload[:current_user_id]
# do something interesting with current_user_id here
end
You already have the answer, what you're doing is the same as when people are accessing the request in models. The current_user is just a method defined on your ApplicationController. When you're not in a controller or other class that inherits from it, you can't access that method.
HttpContext.Current.Request << I would bet a lot that this uses thread storage. Any other solution we find will also be thread storage at some level or another.
Either pull out what you need from the request in the controller and pass it down as parameters, or use thread storage -- but this is inherently dangerous anyway. What if you start using delayed job to do the notifications or something?

how to defined a function in rails 3 and how to call it?

I am new at rails 3 can you tell me how to defined a function in rails 3?
I'm not sure what you're asking... You don't really just define a function and then go on your merry way... Do you understand how the framework works together?
Rails (all rails, not just 3) has a model, a view, and a controller (roughly speaking) that all work together to display a web page. The model describes an object (like a User), the controller describes things you can do with the user (usually CRUD: Create, Read, Update, Destroy) and the view describes how display the user (for example, an html page).
If you wanted to put a function (called "methods" in ruby) in your model, you could do something like:
class User < ActiveRecord::Base
def my_method
return "Hello World"
end
end
If you wanted to call your method, you would need an actual individual user to call it on. For example you could do something like:
u = User.create()
u.my_method
If you wanted the method to apply to all users, not just a single User, you could do a class variable instead, like:
def User.class_method
end
and call it like User.class_method.
Hope this helps...there's a LOT of tutorials out on the web you can look through.

Need guidance in creating Rails 3 Engine/Plugin/Gem

I need some help figuring out the best way to proceed with creating a Rails 3 engine(or plugin, and/or gem).
Apologies for the length of this question...here's part 1:
My company uses an email service provider to send all of our outbound customer emails. They have created a SOAP web service and I have incorporated it into a sample Rails 3 app. The goal of creating an app first was so that I could then take that code and turn it into a gem.
Here's some of the background: The SOAP service has 23 actions in all and, in creating my sample app, I grouped similar actions together. Some of these actions involve uploading/downloading mailing lists and HTML content via the SOAP WS and, as a result, there is a MySQL database with a few tables to store HTML content and lists as a sort of "staging area".
All in all, I have 5 models to contain the SOAP actions (they do not inherit from ActiveRecord::Base) and 3 models that interact with the MySQL database.
I also have a corresponding controller for each model and a view for each SOAP action that I used to help me test the actions as I implemented them.
So...I'm not sure where to go from here. My code needs a lot of DRY-ing up. For example, the WS requires that the user authentication info be sent in the envelope body of each request. So, that means each method in the model has the same auth info hard coded into it which is extremely repetitive; obviously I'd like for that to be cleaner. I also look back now through the code and see that the requests themselves are repetitive and could probably be consolidated.
All of that I think I can figure out on my own, but here is something that seems obvious but I can't figure out. How can I create methods that can be used in all of my models (thinking specifically of the user auth part of the equation).
Here's part 2:
My intention from the beginning has been to extract my code and package it into a gem incase any of my ESP's other clients could use it (plus I'll be using it in several different apps). However, I'd like for it to be very configurable. There should be a default minimal configuration (i.e. just models that wrap the SOAP actions) created just by adding the gem to a Gemfile. However, I'd also like for there to be some tools available (like generators or Rake tasks) to get a user started. What I have in mind is options to create migration files, models, controllers, or views (or the whole nine yards if they want).
So, here's where I'm stuck on knowing whether I should pursue the plugin or engine route. I read Jordan West's series on creating an engine and I really like the thought of that, but I'm not sure if that is the right route for me.
So if you've read this far and I haven't confused the hell out of you, I could use some guidance :)
Thanks
Let's answer your question in parts.
Part One
Ruby's flexibility means you can share code across all of your models extremely easily. Are they extending any sort of class? If they are, simply add the methods to the parent object like so:
class SOAPModel
def request(action, params)
# Request code goes in here
end
end
Then it's simply a case of calling request in your respective models. Alternatively, you could access this method statically with SOAPModel.request. It's really up to you. Otherwise, if (for some bizarre reason) you can't touch a parent object, you could define the methods dynamically:
[User, Post, Message, Comment, File].each do |model|
model.send :define_method, :request, proc { |action, params|
# Request code goes in here
}
end
It's Ruby, so there are tons of ways of doing it.
Part Two
Gems are more than flexible to handle your problem; both Rails and Rake are pretty smart and will look inside your gem (as long as it's in your environment file and Gemfile). Create a generators directory and a /name/name_generator.rb where name is the name of your generator. The just run rails g name and you're there. Same goes for Rake (tasks).
I hope that helps!