Determine given module is rails engine - ruby

Hi I have two modules
Admin
Blog (Blog is a rails engine)
where Admin is a module for namespacing admin features of app, but Blog is a module representing rails engine. Is there a better way to determine which among them is engine, like a function "is_engine?"
Admin.is_engine?
=> false
Blog.is_engine?
=> true
Definately I can have a try catch thing to determine this
def is_engine? module
module::Engine
true
rescue NameError
false
end
here
is_engine? Admin
will return false
is_engine? Blog
will return true
Thanks

I'm not sure I understand what you are trying to do: a Rails Engine is a class (a subclass of Rails::Engine), not a module.
If you have an instance, you could use:
admin.kind_of?(Rails::Engine)
If you have a class, you can use:
Something.ancestors.include?(Rails::Engine)
If what you have is a module, then it cannot be a subclass of Rails::Engine, and it's not an engine.
EDIT
If you have a module or constant something and want to know if there's a constant with a certain name in its namespace, you can use:
something.constants.include?(:Engine)

Related

Is there a way in Sinatra to separate helpers used in views and helpers used in routes?

All helpers in Sinatra can be accessed from both my HAML code and my routes. But I'm finding myself writing two completely separate sets of code for these two.
Ideally I'd like to keep them apart. Currently I have them in two different directories, but that seems kind of pointless. Can anyone suggest a way I can limit the potential damage caused by namespace collision?
At first I thought modules. From the Sinatra readme:
module FooUtils
def foo(name) "#{name}foo" end
end
module BarUtils
def bar(name) "#{name}bar" end
end
helpers FooUtils, BarUtils
But is there any point in actually doing this? Aren't they going to have to share the same namespace inside my Sinatra app?
Some tentative and not-entirely-satisfactory answers:
1) Methods defined in the same way as helpers but without the call to Sinatra::helpers don't appear to be accessible from views, but are accessible from within the Sinatra application block. That is:
require 'sinatra'
module Sinatra
module MyThing
# Helper classes and methods go here
end
helpers MyThing # <- leave this out if you don't want access from views
end
2) You can of course also have MyThingHelpers and MyThingLib modules, instead of just MyThing, to prevent namespace collision.
3) And you can put them in separate subdirectories.
I've yet to be convinced that these represent a comprehensive solution to my concerns. Time and testing will tell, I suppose, unless someone can give me a better answer here.

Loading attributes only once in Grape

I'm little new to Ruby, but I have the following coded using Grape API in Ruby. I have #data = YAML.load() called every time it hits GET /api/v1/foo, is there a way in Grape to only load it once and use it? This way is more optimized and not calling YAML.load() at every time. Should I override the initialize method and put a super() for this operation?
Thanks,
require 'grape'
require 'json'
require "yaml"
module MyProject
CONFIG_FILE = "./config.yml"
class Api < Grape::API
rescue_from :all
prefix 'api'
version 'v1'
format :json
resources :foo do
get do
#data = YAML.load(File.open(MyProject::CONFIG_FILE))
end
end
end
end
The short answer is that Grape doesn't work quite how you think, and attribute variables of the MyProject::Api are not the way forward for your new web service. However, it is an interesting question, and worth exploring why this is so.
If you add a puts self.inspect inside the resources :foo block, and run using rackup, when you call the route you should see that self is in fact a Grape::Endpoint object. Also, no matter what you try to do with instance variables, they will always start in the same state for each request. That is because Grape turns your route definitions into prepared Grape::Endpoint objects, with a lot of the definition data and setup put into a quickly-accessible form (so that it is not figured out on each request). Eventually, on each request, the matching Grape::Endpoint object including your block (and other details you defined for the route) is duplicated before being called, meaning that state is not maintained between requests.
This may seem complicated, but most frameworks covering web service requests will do something similar. Generally you don't want request-handling state to persist between requests. Frameworks with larger scope - e.g. Rails - have places to put more persistent data planned out for you. Grape does not have this defined, which has its pros and cons. One obvious plus point is that you are more free to use whatever other data persistence approach that you wish to.
23tux's answer will sort you out immediately for loading config. Although I'm not entirely sure how ##data becomes accessible to the endpoint block (it may even be creating a closure around the variable).
Longer term, you should look to moving config management out of your MyProject::Api class, and including it as a module via Grape's helpers method (I'm happy to provide an example if you are interested).
Edit: Example based on your current code, but moving config management to a separate module:
require 'grape'
require 'json'
require "yaml"
module MyProject
module Config
CONFIG_FILE = "./config.yml"
##data = nil
def config
##data ||= YAML.load( File.open( CONFIG_FILE ) )
end
end
class Api < Grape::API
rescue_from :all
prefix 'api'
version 'v1'
format :json
helpers MyProject::Config
resources :foo do
get do
config
end
end
end
end
This is one step further, structurally, than 23tux's answer, but is still not completely separating concerns of storage (and caching etc) versus api access. As you progress towards a more sophisticated web service, you will want to keep the Grape route definitions simple, with only a small amount of logic that manages or manipulates the data - well, at least as seen directly in the blocks.
One way to link between your Grape definitions, and other gems that might manage config, logging, authentication and other services, is via Grape's helpers method. Grape also has some built-in helper methods for common tasks.
The main exception to using helpers MyModule to add shared functions into Grape is when you want to manage displaying data objects (aka "models") from your core application. For that you have a few choices, but the grape-entity gem and the present method is not a bad place to start.
If the #data is the same for the whole api, and doesn't change at any time, just use a class variable
require 'grape'
require 'json'
require "yaml"
module MyProject
CONFIG_FILE = "./config.yml"
class Api < Grape::API
##data = YAML.load(File.open(MyProject::CONFIG_FILE))
rescue_from :all
prefix 'api'
version 'v1'
format :json
resources :foo do
get do
puts ##data
end
end
end
end
Not tested, but with this way, you ensure that the data is only loaded once, when your Api class is loaded

Injecting a scope through an association extension in Rails 2.3.17

I'm upgrading from Rails 2.3.5 to 2.3.17 and have come across a pretty obscure problem. I use the following extensions to inject a scope within an association accessor, and provider a custom builder:
module XYZFilterExtension
def in_context(context)
if proxy_owner.context == :abc && context != :admin
scoped(:conditions => {:startup => false})
else
scoped({})
end
end
end
module OtherExtension
def build_with_component_instance(attributes = nil)
attributes ||= {}
attributes.reverse_merge!(:parent_id => proxy_owner.component_instance.id)
instance = build
instance.build_component_instance
instance.attributes = attributes
instance
end
end
has_many :pages, :extend => [ABCExtension, OtherExtension]
In Rails 2.3.5 I could call:
Something.pages.in_context(:abc).build_with_component_instance
and I'd get a Page object (And it's associated component_instance, the build is complicated because it's a polymorphic association being built from the other direction).
Now I get:
undefined method `build_with_component_instance' for #<Class:0x1151dcae8>
Inspecting the scope, the only difference that I could find is that calling proxy_scope on the scope created by in_context() returns the Page model in 2.3.17 and the scope in 2.3.5.
I'm not sure where to go from here. I can't extract the scope out into a module to include in each model because I need to make a decision based on the proxy_owner in the association.
Update: It appears the problem is around extension methods not being available within the context of a scope. Pretty strange but I guess it kind of makes sense. Unfortunately both my scope definition and the build extension require knowledge of their association context. Any ideas welcome :)
I ended up not finding a way to work around this. In the end I had to avoid the bug in the specific situation in which it occurred. Fortunately it was only in a couple of places in the app.

Ruby: add a method to a module from a separate file and autoload it

I'm using the Sorcery library in a rails app. One of its modules is for external authentication, and I need to add a method to that module.
The existing code is here, I want to add the add_provider_to_user method from this patch.
So, I added a file to my lib/modules directory, which I've told rails to autoload. The file is called sorcery_extension.rb and it looks like this:
module Sorcery
module Controller
module Submodules
module External
module InstanceMethods
protected
# If user is logged, he can add all available providers into his account
def add_provider_to_user(provider)
provider_name = provider.to_sym
provider = Config.send(provider_name)
user_hash = provider.get_user_hash
config = user_class.sorcery_config
user = current_user.send(config.authentications_class.to_s.downcase.pluralize).build(config.provider_uid_attribute_name => user_hash[:uid], config.provider_attribute_name => provider)
user.save(:validate => false)
return user
end
end
end
end
end
end
This didn't work. I get undefined method error in my controller (where calling the other sorcery methods works fine).
So, my basic understanding of ruby is you can add methods to an object or module at any time... I think I've copied the nesting of the modules correctly in the file. Do I need to name the module file something different? I'm not really sure how to do this kind of thing, so any help is much appreciated. Thanks!
Your file is never required. You can double check this by typing in the console:
Sorcery::Controller::Submodules::External::InstanceMethods.method_defined?(:add_provider_to_user)
# => will return false, you want true
The reason is that auloading only happens when a constant is unknown in which case Rails will try to autoload it from the different autoloaded paths.
You have to require your file explicitly (e.g. from a file in initializer) and things will work as expected.
Rails convention on requires is that for every module it looks in a directory of the same name.
For your example
module Sorcery
module Controller
module Submodules
module External
module InstanceMethods
If you want to put the module in the lib directory. When it goes to "autorequire" Rails would be expecting it in this path
lib/sorcery/controller/submodules/external/instance_methods.rb
This is why its generally good convention to keep your module nesting shallow. ~ 2 levels deep.

Single Table Inheritance and routing in Ruby on Rails 3.0

I am having some trouble getting routing to play nicely with Single Table Inheritance in my Ruby on Rails application. I am using Ruby 1.9.2 and Rails 3.0.6. This is in development so the back-end is SQLite3, in case that makes a difference.
Let's say I have two products, widgets and sprockets. My application keeps track of bug numbers and support case tickets for both the products but the bugs and support tickets themselves are stored in other systems. There are two separate teams that work on these two products.
I have implemented Single Table Inheritance for the two types of bug records because the validation rules for widget bug numbers and sprockets bug numbers are different (the two teams use different bug tracking systems) and there is a possibility that I will have to add further products to the application that behave wildly differently. Using STI gives me the flexibility to implement additional methods and properties as required.
The widgets team only cares about widgets information and the sprockets team only cares about sprockets information. There is a third team that needs to be able to view the information on both the widgets and the sprockets. The widgets team will access the application using the path /widgets and the sprockets team will access the application using the path /sprockets. I set this up in routes.rb using namespaces:
resources :bugs
namespace "widgets" do
resources :bugs
end
namespace "sprockets" do
resources :bugs
end
I have set up the following models which work as expected when I fire up irb and use WidgetBug.create() or SprocketBug.create():
bug.rb
class Bug < ActiveRecord::Base
end
widget_bug.rb
class WidgetBug < Bug
# Some validation rules
end
sprocket_bug.rb
class SprocketBug < Bug
# Some different validation rules
end
I used scaffolding to create the controller and the view for the bug object, then modified the controller to try to generalize it so it could be used with both widgets bugs and sprockets bugs. For example, the index method looks like this:
def index
# The scaffold code lists all bugs, which is not what we want
# #bugs = Bug.all
# Only return bugs of the subclass we're looking for
#bugs = eval("#{params[:controller].classify}.all")
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #bugs }
end
end
I then used create() to populate the database with several bugs of each type. Unfortunately when I browse to /widgets/bugs, the bugs for both products appear. After some debugging, I determined that the classify call is returning Widgets::Bugs or Sprockets::Bugs, so when I call all on it, it appears to be running against the superclass instead of running against the subclass.
I've reviewed the routing documentation and done quite a bit of searching on Google but I'm still at a loss as to how I can change the routing or the controller to make this work correctly. Any help would be greatly appreciated.
Checkout this post: STI, one controller
Routes
resources :widgets, :controller => "bugs", :type => "Widget"
resources :sprockets, :controller => "bugs", :type => "Sprocket"
# And I don't know if you need this
resources :bugs, :type => "Bug"
Controller
def index
#bugs = params[:type].constantize.all
end
UPD
namespace "widgets" do
resources :bugs, :type => "Widget"
end
namespace "sprockets" do
resources :bugs, :type => "Sprocket"
end
I wrote a blog post on STI in Rails 3 that discusses some common pitfalls and proper work arounds, including the problem you mention. http://www.christopherbloom.com/2012/02/01/notes-on-sti-in-rails-3-0/

Resources