Active Model XML serialization : undefined method `[]' for nil:NilClass - ruby-on-rails

Originally from here, i'm posting a new thread to focus on my issue resolving around the "to_xml" method.
What i'm trying to do : make a conversion from a ruby Object (Whois::Record) to XML.
I am currently using ActiveModel but not ActiveRecord (eg previous thread for reasons)
Here is the relevant controller :
def lookup
domain = params[:domain]
#whois = Request.new
#whois.search(domain)
respond_to do |format|
if #whois != nil
format.html
format.json {render :json => #whois.body}
format.xml {render :xml => #whois}
else
format.html { render :new }
format.json { render json: #request.errors, status: :unprocessable_entity }
end
end
end
Please note that #whois is NOT a Whois::Record object, but a class that contains such object (in the body property)
And the view :
<% if #whois != nil %>
<%= #whois %>
<!--JSON-->
<%= #whois.body.to_json %>
<!--XML-->
<% byebug %>
<%= #whois.to_xml %>
<% end %>
Note that the to_json method works fine, so the fact that ruby throws a nilClass exception is quite weird.
Here is the stacktrace starting from to_xml :
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/xml_mini.rb:148:in _dasherize'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/xml_mini.rb:140:inrename_key'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/xml_mini.rb:119:in to_tag'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/core_ext/hash/conversions.rb:88:inblock (2 levels) in to_xml'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/core_ext/hash/conversions.rb:88:in each'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/core_ext/hash/conversions.rb:88:inblock in to_xml'
/home/nico/.rvmruby (2.1.3) gems/builder-3.2.2/lib/builder/xmlbase.rb:175:in call'
/home/nico/.rvmruby (2.1.3) gems/builder-3.2.2/lib/builder/xmlbase.rb:175:in_nested_structures'
/home/nico/.rvmruby (2.1.3) gems/builder-3.2.2/lib/builder/xmlbase.rb:68:in tag!'
/home/nico/.rvmruby (2.1.3) gems/activesupport-4.1.6/lib/active_support/core_ext/hash/conversions.rb:87:into_xml'
app/models/request.rb:26:in `to_xml'
Byebug gives me a lead as such :
to_xml > ActiveSupport::SafeBuffer::OutpuBuffer#safe_concat
153: def safe_concat(value)
=> 154: raise SafeConcatError unless html_safe?
155: original_concat(value)
156: end
note : html_safe? is set at 'true' here, and value equals "\t"
original_concat
File activesupport/lib/active_support/core_ext/string/output_safety.rb, line 132
Alias to original_concat
def concat(value)
if !html_safe? || value.html_safe?
super(value)
else
super(ERB::Util.h(value))
end
end
And when i step over i come back to the to_xml method, that's throwing a tantrum about not having a class to call upon methhods. I would be grateful for any help, thanks.
Edit
Here is the class Request from my model :
#This is a generic class for checking Key authenticity and sending requests to the engine
#Furthermore, this class will contain the WHOIS response in body
include ActiveModel::Model
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
attr_accessor :body
def attributes
{body => nil}
end
def to_xml(options = {})
to_xml_opts = {:skip_types => true} # no type information, not such a great idea!
to_xml_opts.merge!(options.slice(:builder, :skip_instruct))
# a builder instance is provided when to_xml is called on a collection of instructors,
# in which case you would not want to have <?xml ...?> added to each item
to_xml_opts[:root] ||= "instructor"
self.attributes.to_xml(to_xml_opts)
end
def search(domain)
# since rails compiles the code before executing a search once,
# we have to catch niClass exceptions and such
if domain != ( nil && true && "" )
c = Whois::Client.new
self.body = c.lookup(domain)
end
end
I've used this as from what i've understood XML tries to define a type for each attribute, and has problems with named objects. Here's the thread about to_xml and objects in rails

Related

respond_with having issue with Rails 5

I am upgrading my Rails app from 4.1.1 to 5.1.4.
I am using roar-rails gem to parsing and rendering REST documents. I am facing some issues as responders gem has been extracted to separate gem.
respond_with has been moved to 'responders' gem.
My rails 4 code lookgs like this:
PostsController:
class PostsController < ApplicationController
respond_to :json
def index
posts = current_user.posts
respond_with posts, :represent_with => PostsRepresenter, current_user: current_user
end
end
My representers for Post
module PostsRepresenter
# Rails 4 code
# include Roar::Representer::JSON::HAL
# Rails 5 code (after adding responders) --------
include Roar::JSON
include Roar::Hypermedia
# Rails 5 code --------
collection(
:post,
class: Post,
extend: PostRepresenter,
embedded: true)
link :make do |args|
p "............. #{args.inspect}"
# In rails 4, args are coming correctly what is passing from Controller
# But in rails 5, args is coming `nil`
posts_path if args[:current_user].can_create?(Post)
end
end
Post representer
module PostRepresenter
# Rails 4 code
# include Roar::Representer::JSON::HAL
# Rails 5 code (after adding responders) --------
include Roar::JSON
include Roar::Hypermedia
# Rails 5 code --------
property :title
property :description
property :author
link :self do |args|
post_path(id) if args[:current_user].can_read?(self)
end
link :remove do |args|
post_path(id) if args[:current_user].can_delete?(self)
end
link :edit do |args|
post_path(id) if args[:current_user].can_update?(self)
end
end
I am facing issue with args which are passing through Controller,
after rails 5, its coming nil.
I have debug the issue and found that in responders gem, options are coming in respond_with method, but I think it could not send it to roar-rails.
/path-to-gem/vendor/responders-master/lib/action_controller/respond_with.rb
Here is snippet:
def respond_with(*resources, &block)
if self.class.mimes_for_respond_to.empty?
raise "In order to use respond_with, first you need to declare the " \
"formats your controller responds to in the class level."
end
mimes = collect_mimes_from_class_level
collector = ActionController::MimeResponds::Collector.new(mimes, request.variant)
block.call(collector) if block_given?
if format = collector.negotiate_format(request)
_process_format(format)
options = resources.size == 1 ? {} : resources.extract_options!
options = options.clone
options[:default_response] = collector.response
p "====================== options :: #{options.inspect}"
# Options are correct till here but coming `nil` on representers
(options.delete(:responder) || self.class.responder).call(self, resources, options)
else
raise ActionController::UnknownFormat
end
end
Please let me know what needs to be done here that make args
available in representers
respond_with was deprecated from rails 4.2.1.
https://apidock.com/rails/ActionController/MimeResponds/respond_with

why I got the error "Couldn't find article with id=ni-hao-wo-zhen-de-henhaoma" when using stringex?

I want to use stringex for more friendly url. Now my steps as follows:
(1) In the model called article:
acts_as_url :title, :url_attribute => :slug
def to_param
slug
end
(2) articles#show:
def show
debugger
show! do |format|
format.html # show.html.erb
format.json { render json: #article }
end
end
(3) the articles/_article.html.erb includes:
<%= link_to(article_url(article)) do %>
...
<% end %>
and correctly generates html tag, such as:http://localhost:8000/articles/ni-hao-wo-zhen-de-henhaoma
When I click the link generated in (2), I got the error:
ActiveRecord::RecordNotFound in ArticlesController#show
Couldn't find Article with id=ni-hao-wo-zhen-de-henhaoma
I set a breakpoint in the entry of ArticlesController#show, but the above error come out before it.
What else steps should I do?
Updated: according to #jvnill's reminding, I think the backtrace maybe help:
activerecord (3.2.21) lib/active_record/relation/finder_methods.rb:344:in `find_one'
activerecord (3.2.21) lib/active_record/relation/finder_methods.rb:315:in `find_with_ids'
activerecord (3.2.21) lib/active_record/relation/finder_methods.rb:107:in `find'
activerecord (3.2.21) lib/active_record/querying.rb:5:in `find'
inherited_resources (1.4.1) lib/inherited_resources/base_helpers.rb:51:in `resource'
cancancan (1.10.1) lib/cancan/inherited_resource.rb:12:in `load_resource_instance'
cancancan (1.10.1) lib/cancan/controller_resource.rb:32:in `load_resource'
cancancan (1.10.1) lib/cancan/controller_resource.rb:25:in `load_and_authorize_resource'
cancancan (1.10.1) lib/cancan/controller_resource.rb:10:in `block in add_before_filter'
Please go through the guide first so you can understand the flow better.
http://guides.rubyonrails.org/v3.2.13/action_controller_overview.html#filters
To answer your error, what happens is that #article is being set in a before_filter and it most probably finds the record by id
#article = Article.find(params[:id])
Since params[:id] is the article slug, what you want to do is find by slug instead. So skip that before_filter for the show action and create another before_filter specifically for show action. Something like the following.
before_filter :fetch_article, except: :show
before_filter :fetch_article_by_slug, only: :show
private
def fetch_article
#article = Article.find(params[:id])
end
def fetch_article_by_slug
#article = Article.find_by_slug!(params[:id])
end
UPDATE
Using the inherited_resources gem, you may want to implement your own show action (the following code is untested and I can't vouch for it since I've never used the gem before)
actions :all, except: [:show]
def show
#article = Article.find_by_slug!(params[:id])
end

Catching exceptions in a render call from a rails helper

This is for a rails 4.0.2 application running ruby 2.0.0-p353.
I have a helper that has the following method
def render_feed_row(activity_item)
begin
if activity_item.type == "comment"
render "newsfeed/comment", :item => activity_item
elsif activity_item.type == "post"
render "newsfeed/post", :item => activity_item
else
raise NameError
end
rescue NameError => e # note: NoMethodError is a subclass of NameError
render "newsfeed/other", :item => activity_item
end
end
But if a NoMethodError is raised in the newsfeed/post partial, it is not caught in this helper. Why is that? It don't render newsfeed/other, it actually raises an exception.
I've just checked with a simplified version of your code, and it worked correctly.
def render_feed_row
raise NoMethodError
rescue NameError
puts "kaboom"
end
render_feed_row
# => kaboom
However, please note it's a very bad practice to use exceptions for control flow in such way. Moreover, if you really want to use exceptions, you should create your own classes, not use NoMethodError or NameError that have specific meanings in Ruby programs.
Here's a more clean version of your method
def render_feed_row(activity_item)
case (type = activity_item.type)
when "comment", "post"
render "newsfeed/#{type}", item: activity_item
else
render "newsfeed/other", item: activity_item
end
end
Or a more concise version
def render_feed_row(activity_item)
name = case activity_item.type
when "comment", "post"
activity_item.type
else
"other"
end
render "newsfeed/#{name}", item: activity_item
end
Using exceptions for control flow is slow. Why not just:
def render_feed_row(activity_item)
partial = ['comment', 'post'].include?(activity_item.type) ?
activity_item.type : 'other'
render "newsfeed/#{partial}", :item => activity_item
end

rails constructor "def initialize" with attributes: correct way to pass in model

Hi I have a model called "Listing".
Here is the constructor for the model:
def initialize(business)
puts 'inside Listing.initialize'
#name = business.name
#telephone = business.telephone
puts 'Created a new Listing'
end
I have a controller called "listings_controller"
I have is another model called "Business". Inside the "listing_controller" I have a method in which I would like to instantiate a "Listing" with attributes of a "Business".
Here is the code that does that in a "listings_controller"
def create_listings
self.get_all
#businesses.each do |business|
Listing.create(business)
end
end
def show
self.create_listings
#listings = Listing.all
respond_to do |format|
format.html #show.html.erb
end
end
This initialization method is not working.Im getting this exception:
wrong number of arguments (2 for 1)
Rails.root: /Users/AM/Documents/RailsWS/cmdLineWS/Businesses
Application Trace | Framework Trace | Full Trace
app/models/listing.rb:53:in initialize'
app/controllers/listings_controller.rb:18:inblock in create_listings'
app/controllers/listings_controller.rb:17:in each'
app/controllers/listings_controller.rb:17:increate_listings'
app/controllers/listings_controller.rb:26:in `show'
How can I fix this?
Thanks
You could try (pseudocode/untested):
def initialize(business)
puts 'inside Listing.initialize'
#attributes.merge(business.attributes)
puts 'Created a new Listing'
end

Sending params to GET request in Ruby on Rails 2.3.x

I'm new to rails and I'm currently using 2.3.8. I'm designing a web service for an iOS app.
As I'm normally a client side iPhone developer, my knowledge of server side implementation is shamefully minimal.
The problem I'm having is that I'm trying to pass some params in a GET request to the index action in one of my controllers. This is routed using the default
map.resources :dishes
where dishes is the name of the controller, created with scaffold.
I would like to pass multiple params to either a new action or to the index, which will allow me to filter the dish objects to return.
The index method looks like
def index
if(params[:latitude])
#min = 0.5 - 1
#max = 0.5 + 1
#locations = Location.find(:all, :conditions => [":latitude > ? AND :latitude < ?", #min, #max])
#dishes = new Array
#locations.each do |loc|
#dishes = #dishes + loc.dishes
end
respond_to do |format|
format.html # index.html.erb
format.json {render :json => #dishes.to_json(:except => [ :user_id, :location_id , :like_id], :include => { :user => { :only => [:id, :name] } } ) }
end
else
#dishes = Dish.all
respond_to do |format|
format.html # index.html.erb
format.json {render :json => #dishes.to_json(:except => [ :user_id, :location_id , :like_id], :include => { :user => { :only => [:id, :name] } } ) }
end
end
end
I am currently getting the following error when I pass in an extra param
ArgumentError in DishesController#index
wrong number of arguments (1 for 0)
The full error:
ArgumentError in DishesController#index
wrong number of arguments (1 for 0)
RAILS_ROOT: /Users/jon/Documents/Dev/Research/FF5_Rails_Test/FF5
Application Trace | Framework Trace | Full Trace
/Users/jon/Documents/Dev/Research/FF5_Rails_Test/FF5/app/controllers/dishes_controller.rb:9:in `new'
/Users/jon/Documents/Dev/Research/FF5_Rails_Test/FF5/app/controllers/dishes_controller.rb:9:in `index'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:1331:in `send'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:1331:in `perform_action_without_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:617:in `call_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
/Library/Ruby/Gems/1.8/gems/activesupport- 2.3.8/lib/active_support/core_ext/benchmark.rb:17:in `ms'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/core_ext/benchmark.rb:17:in `ms'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/rescue.rb:160:in `perform_action_without_flash'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/flash.rb:151:in `perform_action'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:532:in `send'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:532:in `process_without_filters'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/filters.rb:606:in `process'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:391:in `process'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/base.rb:386:in `call'
/Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/routing/route_set.rb:438:in `call'
Request
Parameters:
{"format"=>"json",
"latitude"=>"0.5"}
Show session dump
Response
Headers:
{"Content-Type"=>"",
"Cache-Control"=>"no-cache"}
I realise this goes slightly against the RESTful design of Rails but I couldn't work out another way to do it.
Again, I'm a new to rails / web service dev so if you have any tips I would welcome them.
Thanks.
You have
#dishes = new Array
which is not Ruby unfortunately :) There are three ways to create an instance of Array
#dishes = Array.new
#dishes = []
#dishes = Array( nil )
also pay attention to
/Users/jon/Documents/Dev/Research/FF5_Rails_Test/FF5/app/controllers/dishes_controller.rb:9:in 'new'
/Users/jon/Documents/Dev/Research/FF5_Rails_Test/FF5/app/controllers/dishes_controller.rb:9:in 'index'
which tells you that error happened in new not in index

Resources