enumerations_mixin gem depends on deprecated method
here's the guilty line
what would be correct approach to patch it?
Quite a lot of patching I am afraid. This method has been replaced by class_attribute, however it works slightly different. Previously it was enough to use write_inheritable_attribute to create new class param, now you need to declare it first and then assign value.
On line 17 it is using 'write_inheritable_attribute` to set those values. It should now read
class_attribute :"acts_enumerated_#{key}" unless respond_to? "acts_enumerated_#{key}"
self.send(:"acts_enumerated_#{key}=", options[key])
Then, everywhere it is using read_inheritable_attribute(:attribute_name) just use self.attribute_name.
The only problem with this is that 'read_inheritable_attribute` returned nil if attribute is not set and the approach above will throw an error. You will notice that all read methods has default value, like (line 56):
read_inheritable_attribute(:acts_enumerated_on_lookup_failure) || :enforce_strict_literals
You will need to look for all those defaults and enforce them within acts as enumerated method:
def acts_as_enumerated(options = {})
valid_keys = [:conditions, :order, :on_lookup_failure]
default_options = {<all the default values from the code>}
options = default_options.merge options
options.assert_valid_keys(*valid_keys)
valid_keys.each do |key|
write_inheritable_attribute("acts_enumerated_#{key.to_s}".to_sym, options[key]) if options.has_key? key
end
However this is not a perfect design. I would probably define class_attribute enumerated_options within append_features method, put all the options there as a hash instead of creating class_attribute for each option. This is absolutely up to you though.
Also please notice that this gem has been written over 4 years ago, and this method might be not the only deprecated one. I am not entirely sure what this gem is supposed to do, but it might be easier to rather implement what you need rather than to use it.
Clone the gem's repo locally and use it in your rails project as a path to a local gem. So specify in your gemfile:
gem :enumerations_mixin, :path => '/local/path/to/gem'
When you will have the gem patched, fork it on github, replace gems origin in /local/path/to/gem/.git/config, push your changes to your fork, and replace that line in your gemfile to the follownig:
gem :enumerations_mixin, :github => 'your_acoount/enumerations_mixin'
Issue the pull-request to the root repo of the gem, and when the request will be accepted, replace that line in your gemfile to the follownig:
gem :enumerations_mixin, :github => 'protocool/enumerations_mixin'
When the gem will have been released the line can be replaced to:
gem :enumerations_mixin, '~> <new_verison>'
Related
I have a GoogleTranslate service that translates text in my app. The feature works on localhost but in production it raises
uninitialized constant Google::Cloud in my app/helpers/google_translations_helper.rb:4:in `initialize'...
Here is the Gemfile related part :
# use of google API
gem 'google-api-client', '~> 0.11', :require =>
'google/apis/analyticsreporting_v4'
gem 'omniauth-google-oauth2'
gem "google-cloud-translate"
And here is the helper/service initializer:
module GoogleTranslationsHelper
class GoogleTranslate
def initialize
#translation_service = Google::Cloud::Translate.new
end
def translate(text)
#translation_service.translate text.to_s, from: "fr", to: "en"
end
end
end
I wonder if I'm not missing something about gem version or something like that..
Does someone had the problem already?
I assume you are running Rails. Make sure you include:
require "google/cloud/translate"
somewhere reasonable, either at the top of the file that creates the client object (app/helpers/google_translations_helper.rb in your case), or in a global initialization file such as config/application.rb. (The google-cloud-translate library, like most libraries, needs you to require it before you can use it. See the snippets in the documentation for examples.)
It's not completely clear to me why this is working differently between your development and production environments, but there are usually a lot of differences in the initialization procedure between the two environments so it's not too surprising. Just make sure you're in the habit of requiring any library before using it.
As a side note, I would also recommend updating your Gemfile to call for more recent versions of the Google client libraries. Or at least make sure you've done a recent bundle update. As of this writing, google-api-client 0.11 is more than 2 years old; the newest is 0.30.8. And google-cloud-translate is at 1.3.0. It is always possible there are issues if you're on old versions.
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
As part of the RSpec, i need to reference a file contained in a gem I am depending on (call it gem foo). I control gem foo, so I can make changes to it as needed.
Gem 'foo' contains a file that I need to reference with in the a rspec spec. Is there a reasonably stable RubyGem or Bundler API to figure out 'foo' base directory?
Assuming 'foo' is already required in my Gemfile:
in Gemfile:
gem 'foo'
I want to do something like this (in something_spec.rb):
filename = File.expand_path('examples/xml/result.xml', Gem.gem_base_path('foo'))
What is gem_base_path API call?
I would recommend creating a function in your gem to do this:
module Foo
class Configuration
def self.result_xml_path
File.realpath("../examples/xml/result.xml")
end
end
end
You can then do the following in your spec:
filename = Foo::Configuration.result_xml_path
This is much safer since you are getting all the information from the gem. It also looks cleaner.
This may do what you need without ant need to touch the 'foo' gem:
matches = Gem::Specification.find_all_by_name 'foo'
spec = matches.first
filename = File.expand_path('examples/xml/result.xml', spec.full_gem_path)
I have used this code to make something similar to what you need (namely loading in my specs some factories defined in a gem used by my project)
I'm using the Rails gem SimpleForm, but I think my question may be applicable to any gem.
https://github.com/plataformatec/simple_form
It has a lot of great features and customization, but I'm looking to go a bit further. For example, I really wish the markup generated had no default classes inserted into it, but I'd still like the ability to insert my own manually. I found that I could remove some of the classes by commenting out lines in the gem files. However this is outside of my project-- I would want a DRY solution that will stay with my project when I deploy to production, preferably without having to pack all of my gems.
I imagine this is a common situation that could apply to any gem, and I should be able to override any gem wholly or partially probably by adding customs files in my project that override the gem... but I'm not sure how.
Any help would be appreciated! Thanks.
Are you talking about monkey patching? Say your gem has a class in a file
# simple_form_gem/lib/some_file.rb
class A
def some_method
puts 'A'
end
end
If you want to change the output of #some_method then you can create an initializer file and do
# config/initializers/my_monkey_patch_for_simple_form_gem.rb
class A
def some_method
puts 'duck punching'
end
end
Your monkey patch will only affect A#some_method, and not other methods in A. Just make sure the output of your monkey patch won't break something else in the gem.
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 :)