How to get the xml output of a view/controller as string within the same controler
This is the routes file
routes.rb
map.ccda '/ccda/ccda_patient_search', :controller => 'ccda', :action => :ccda_patient_search
map.ccda '/ccda/:id.:format', :controller => 'ccda', :action => :index
ccda_controller.rb
class CcdaController < ApplicationController
def index
#
# some process
# result = User.find(params[:id]).result
#
#ccda = result
respond_to do |format|
format.xml { render :layout => false, :template=> "index.xml.builder" }
format.any { redirect_to login_url }
end
end
def get_xml
# render_to_string 'index', :layout=>false, :formats=>[:xml], :locals=>{:id=>147} => Not working
# render_to_string '147.xml' => Not working
#
# How do I get the output of 'http://localhost/ccda/147.xml' here???
#
end
end
I will use the url localhost/ccda/147.xml to view/generate the users result as xml
Now I want the output of that url as a string without returning to browser
I've tried to get it from same controller using render_to_string method with diffrent parameters but nothing seems to work
FYI: I am using rails 2.3.12 and Builder::XmlMarkup API
How about using the following call (inside controller, have taken the known options from your question):
render_to_string(:template => 'ccda/index.xml.builder', :layout => false, :id => 147)
Due to the documentation, this will work up to Rails version 2.3.8, so I don't know if it is available any more in Rails 2.3.12 you are using.
PS: How about upgrading to at least last version of Rails 3? I don't have a change to test my solution, so it is guesswork more or less.
How about this below?
render_to_string :controller => 'ccda_controller', :action => 'index', :id => 147, :format => :xml
Finally I've found that we need to specify the view file manually because by default rails will be looking for index.erb so what I've done is this
render_to_string( :action=>"index", :view => "/ccda/index.xml.builder", :format=>:xml,:layout=>false,:id=>146, :template=>"/ccda/index.xml.builder" )
specifying :view and :template manually solved my problem
Related
I am having a normal HTML frontend and a JSON API in my Rails App. Now, if someone calls /api/not_existent_method.json it returns the default HTML 404 page. Is there any way to change this to something like {"error": "not_found"} while leaving the original 404 page for the HTML frontend intact?
A friend pointed me towards a elegant solution that does not only handle 404 but also 500 errors. In fact, it handles every error. The key is, that every error generates an exception that propagates upwards through the stack of rack middlewares until it is handled by one of them. If you are interested in learning more, you can watch this excellent screencast. Rails has it own handlers for exceptions, but you can override them by the less documented exceptions_app config option. Now, you can write your own middleware or you can route the error back into rails, like this:
# In your config/application.rb
config.exceptions_app = self.routes
Then you just have to match these routes in your config/routes.rb:
get "/404" => "errors#not_found"
get "/500" => "errors#exception"
And then you just create a controller for handling this.
class ErrorsController < ActionController::Base
def not_found
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "not-found"}.to_json, :status => 404
else
render :text => "404 Not found", :status => 404 # You can render your own template here
end
end
def exception
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "internal-server-error"}.to_json, :status => 500
else
render :text => "500 Internal Server Error", :status => 500 # You can render your own template here
end
end
end
One last thing to add: In the development environment, rails usally does not render the 404 or 500 pages but prints a backtrace instead. If you want to see your ErrorsController in action in development mode, then disable the backtrace stuff in your config/enviroments/development.rb file.
config.consider_all_requests_local = false
I like to create a separate API controller that sets the format (json) and api-specific methods:
class ApiController < ApplicationController
respond_to :json
rescue_from ActiveRecord::RecordNotFound, with: :not_found
# Use Mongoid::Errors::DocumentNotFound with mongoid
def not_found
respond_with '{"error": "not_found"}', status: :not_found
end
end
RSpec test:
it 'should return 404' do
get "/api/route/specific/to/your/app/", format: :json
expect(response.status).to eq(404)
end
Sure, it will look something like this:
class ApplicationController < ActionController::Base
rescue_from NotFoundException, :with => :not_found
...
def not_found
respond_to do |format|
format.html { render :file => File.join(Rails.root, 'public', '404.html') }
format.json { render :text => '{"error": "not_found"}' }
end
end
end
NotFoundException is not the real name of the exception. It will vary with the Rails version and the exact behavior you want. Pretty easy to find with a Google search.
Try to put at the end of your routes.rb:
match '*foo', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, ['{"error": "not_found"}']] }
What used to work with Rails 3.1.0 was:
class MyController < ApplicationController
...
def myAction
...
data = render_to_string( :template => "reports/report.xml.builder", :layout => false)
...
end
end
With Rails 3.2 I am getting a deprecation warning. How do I render an arbitrary xml builder view with Rails 3.2?
Instead of
render(:template => "reports/report.xml.builder", :layout => false)
Rails 3.2 wants
render(:template => “reports/report”, :formats => [:xml], :handlers => :builder, :layout => false)
In my case I've '_test.xm.builder' partail so I have to use render_to_string it work like this
render_to_string(partial: "/assignments/test", :formats => [:xml], :locals=> {:abc=>'xyz'})
this will cure :)
I've added a method inside of an existing Rails controller (reports_controller) to handle a specific action that is beyond the basic scope of REST. Let's call that action 'detail':
def detail
#report = Report.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #report }
end
end
I added the appropriate layout page (detail.html.erb) and routing to make sure that I can access the page from anywhere. This is how my route looks like:
map.connect "reports/:action", :controller => 'reports', :action => /[a-z]+/i
Right now I'm able to access any of the detail pages. An example page would look like this: http://127.0.0.1:3000/reports/detail/8
Now, I'm trying to create a link from the main Report index page to the detail pages, but when using the code below:
<%= link_to "Details", {:controller => "reports", :action => "detail", :id => #report }, {:title => "see details for this report"} %>
The link that is created does not include the report's ID on it an looks like this:
http://127.0.0.1:3000/reports/detail
Any idea of what's wrong with what I'm doing?
Thanks!
I think you might be looking for :member:
map.resources :reports, :member => { :detail => :get }
Using link_to:
link_to "Detail", detail_report_path(#report)
Syntax error, maybe?
Try no comma right after #report
def show
render :text => params.inspect
end
What is render :text =>?
What is render, :text, and the =>?
Are they standard ruby?
The syntax you see used in that code snippet is not limited to render(), but it is common with many other Ruby on Rail methods.
The method is accepting a hash map, using a simplified syntax.
The code is equivalent to
def show
render({:text => params.inspect})
end
Other code snippets that include the same syntax are:
def sign
Entry.create(params[:entry])
redirect_to :action => "index"
end
url_for :controller => 'posts', :action => 'recent'
url_for :controller => 'posts', :action => 'index'
url_for :controller => 'posts', :action => 'index', :port=>'8033'
url_for :controller => 'posts', :action => 'show', :id => 10
url_for :controller => 'posts', :user => 'd', :password => '123'
def show
#article = Article.find(params[:id])
fresh_when :etag => #article, :last_modified => #article.created_at.utc, :public => true
end
render is rails API. See doc. For everything else, let me recommend you something and you will understand.
the syntax you have posted is a prettier way of writing
render({:text => "hello world"})
basically, you are calling a method, passing in a Hash object (which is a collection of key value pairs). The hash contains 1 pair, with a key of :text (: indicating it is a symbol called text), the value being a string of "hello world"
I think you should really be reading the ruby getting started guides before digging too deep in to rails.
The render :text idiom is for rendering text directly to the response, without any view. It's used here for debugging purposes, it's dumping the contents of the params hash to the response page without going through the page view.
render :text => "hello world!"
Renders the clear text "hello world" with status code 200
This is what the :text => ... means
refer http://api.rubyonrails.org/classes/ActionController/Base.html
I've got a simple Rails application running as a splash page for a website that's going through a transition to a new server. Since this is an established website, I'm seeing user requests hitting pages that don't exist in the Rails application.
How can I redirect all unknown requests to the homepage instead of throwing a routing error?
I just used route globbing to achieve this:
map.connect "/*other", :controller => "pages", :action => "index"
Note that this route should be at the end of routes.rb so that all other routes are matched before it.
You can use the following ways to handle errors in a common place. Place this code in you ApplicationController
def rescue_404
#message = "Page not Found"
render :template => "shared/error", :layout => "standard", :status => "404"
end
def rescue_action_in_public(exception)
case exception
when CustomNotFoundError, ::ActionController::UnknownAction then
#render_with_layout "shared/error404", 404, "standard"
render :template => "shared/error404", :layout => "standard", :status => "404"
else
#message = exception
render :template => "shared/error", :layout => "standard", :status => "500"
end
end
Modify it to suit your needs, you can have redirects as well.
HTH