Does to_json require parameters? what about within rails?
I started getting the error "wrong number of arguments (0 for 1)" when doing myhash.to_json
Unfortunately I'm not sure when this error started happening, but I guess it relates to some versions of either rails or the json gem. I suppose my code (in a rails controller) is using the ActiveSupport::JSON version of to_json, rather than the to_josn method supported by the json gem. ActiveSupport::JSON vs JSON
In environment.rb I have
RAILS_GEM_VERSION = '2.3.2'
and also
config.gem "json", :version=> '1.1.7'
It's just a simple hash structure containing primitives which I want to convert in my controller, and it was working, but now I can't seem to run to_json without passing parameters.
Do you have your own version of to_json defined in a model that doesn't take args? If so, make it accept *args or opts = {}
If ActiveSupport in that version of rails has to_json, why use a gem? The Gem probably redefines Object#to_json to require arguments and thats why you are getting an error.
Look in the code of the json Gem and find where to_json is defined to verify this.
to_json does not require parameters, when you're using the version provided within rails (ActiveSupport::JSON) So that error message shows that it must be trying to call the to_josn method defined in the json gem.
So my actual source of confusion was around the way rails loads these libraries.
It will load the json gem and use it within a controller, even if I don't have a line saying 'require json' because rails loads gems as defined in environment.rb, so in fact I needed to remove the line
config.gem "json", :version=> '1.1.7'
...from my environment.rb . My code had been broken since I had added that. Confusingly I do need that gem, but only for scripting I'm doing outside of rails.
Related
I'm new to Ruby on Rails and I'm looking at an application that has a variable called current_teacher. I cannot seem to find where this is set. Everywhere I look the code seems to read from it but where is it set. Is this one of those things that Rails does for you. There is a mode and a table called teachers, so I'm sure this has something to do with it.
I'm very confused by statements like the following, can someone tell me how Rails does this?
if current_teacher.can_request_fieldtrip
Suppose you have a controller like :
class ClientsController < ApplicationController
def new
if current_teacher.can_request_fieldtrip
# code
end
end
end
Here is debugging tips :
(a) put this in your Gemfile and do bundle install :
`gem 'pry-rails', :group => :development`
(b) Put the line binding.pry just before the if statement.
(c) Start rails server using rails s.
(d) Hit the browser like http://localhost:3000/new
(e) Now you will be in the Pry console. Just do in the console,
method(:current_teacher).source_location
And the above line tell you where the method has been defined.
Documentation of Method#source_location
Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native)
Rails does not support authentication by itself, however there are a lot of 'add-ons' that rails can use. These 'add-ons' are called gems. This can be a little confusing because you can't actually see their code inside your project folder.
If you open a file called "Gemfile" (it should be in your project folder) you can see a list of gems that you use. Try searching their names on google, you will probably find official web page that contains it's documentation. That way can learn what they do and how to use them.
current_teacher method smells like "Devise" gem
https://github.com/plataformatec/devise
I'm not sure about can_request_fieldtrip, this could be a custom method defined in Teacher model.
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
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>'
I have a method like this in rails app:
def current_user
return #current_user if #current_user.present?
#current_user = current_user_session && current_user_session.record
end
I haven't used the .present? method before so I went into my interactive ruby shell to play around with it.
Whenever I use xxx.present? it returns a NoMethodError. It doesn't matter if xxx is a string, number, array anything.
How can I use this method?
present is a method provided by ActiveSupport. It is not a part of core ruby. That is why you are not able to use it in the ruby shell. To play around with it, you will need to require the relevant libraries in your console (e.g. irb / pry):
require 'active_support'
require 'active_support/core_ext'
This way, you will have access to all the utility methods provided by activesupport.
present is a rails method, not ruby.
try using rails c instead of irb to use it in your console.
As mentioned above, .present is not in the ruby standard library. Instead, it's in active_support (docs.)
To use active_support, first install the gem, then require it in irb or your ruby script. More information on how to selectively load activesupport extensions can be found in the Rails guides.
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 :)