XML => HTML with Hpricot and Rails - ruby-on-rails

I have never worked with web services and rails, and obviously this is something I need to learn.
I have chosen to use hpricot because it looks great.
Anyway, _why's been nice enough to provide the following example on the hpricot website:
#!ruby
require 'hpricot'
require 'open-uri'
# load the RedHanded home page
doc = Hpricot(open("http://redhanded.hobix.com/index.html"))
# change the CSS class on links
(doc/"span.entryPermalink").set("class", "newLinks")
# remove the sidebar
(doc/"#sidebar").remove
# print the altered HTML
puts doc
Which looks simple, elegant, and easy peasey.
Works great in Ruby, but my question is: How do I break this up in rails?
I experimented with adding this all to a single controller, but couldn't think of the best way to call it in a view.
So if you were parsing an XML file from a web API and printing it in nice clean HTML with Hpricot, how would you break up the activity over the models, views, and controllers, and what would you put where?

Model, model, model, model, model. Skinny controllers, simple views.
The RedHandedHomePage model does the parsing on initialization, then call 'def render' in the controller, set output to an instance variable, and print that in a view.

I'd probably go for a REST approach and have resources that represent the different entities within the XML file being consumed. Do you have a specific example of the XML that you can give?

Related

Javascript not executing (I included format.js)

I added format.js to my controller, yet I still cannot get the js in index.js.erb to execute when I view my index page. The only thing I can figure out is that it must be because of the model name. I had to add
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'business', 'businesses'
end
to my inflections.rb file...because my model is called Business.
my views/js are located at views/businesses/*
Please help before I pull my hair out!
All I have in the index.js.erb file is:
alert(1);
Obviously the goal is that I will get an alert when I finally get the issue fixed, letting me know it is working.
How are you calling your index page? If you visit the index page from your your browser it won't render index.js. That's the whole point behind using format. You will have to call your index method using javascript(something like an ajax call). Your model name does not have anything to do with it.
Javascript execution has nothing to do with your model names. Nor is the inclusion of your JS files done based on the name of the controller or model. If you are using the asset pipeline you need the following.
Assuming that index.js is in /assets/javascripts/index.js, add the following to the /app/assets/javascripts/application.js
//= require ./index
If you don't understand how this works, you may wish to go through the Ruby on Rails Guide for the Asset Pipeline, found here: http://guides.rubyonrails.org/asset_pipeline.html
As a side note, with your inflections usage, I would recommend that if you are going to use a framework like Rails, try and use conventions that come with it. It will save you heartache in future. Name your model business so that your table is called businesses. Unless you really want something like this:
has_one :businesses

rspec populating a variable with data from an external file

I'm still new top rspec, so please excuse if this is an easy one but I wasn't able to find an answer on Google. I have a library module that handles parsing some data from an API response. I have written tests, and all that works fine, however I'd like to move the fake API response data into an external file since it's pretty long and makes the test harder to read. I looked at fixtures and factories, but those are really for models, and this is just a really long xml snippet. My current test looks something like this
describe :my_test do
let(:my_var) { REALLY_LONG_XML_SNIPPET}
....test code...
end
How can I move REALLY_LONG_XML_SNIPPET into an external file?
This is what I use in my specs:
let(:doc) { IO.read(Rails.root.join("spec", "fixtures", "api_response.xml")) }
It will copy the file's contents into a string.
Note that I have turned off the default ActiveRecord fixtures for RSpec, so I put my fixtures in that directory instead.
Update: with Rspec Rails 3.5 and newer
one can also use file_fixture
let(:doc) { file_fixture("api_response.xml").read }
for
files stored in spec/fixtures/files by default
but file location can be customized.

What is the simplest way to make a group of methods available to several Rails applications

tl;dr
What's a simple way I can create a view helpers module I can use in many apps?
What file, located where, loaded how?
I'm on Rails 2.3.11.
I have a bunch of view helper methods. Here's an example of one of them:
# Render form input fields to add or edit a ZIP code.
def render_zip_code_fields( model_instance )
# Bla bla bla ...
end
I have about 20 or so that I've developed over the years and often use in various applications. I'd like to wrap them all up in one file that I can just drop into and app and then be able to call them in my views.
Why not just copy-and-paste them into application_helper.rb? That just doesn't feel right to me. It seems like it should be a separate file.
In fact I tried creating in /lib...
# /lib/my_view_helpers.rb
module MyViewHelpers
# ...
end
And then in application_helper.rb I put...
include MyViewHelpers
But I got a lot of "uninitialized constant MyViewHelpers errors. Maybe a syntax error? I don't think I need to require my_view_helpers.rb first because it's in /lib. Everything in there gets loaded automatically, right?
So what's the right way to do this optimizing for simplicity?
Sorry this is so long. I get verbose when I'm tired.
As of Rails 3, /lib is no longer on the default load path. You will need to put the following line in the Application class in config/application.rb.
config.autoload_paths += ["#{config.root}/lib"]
An alternative would be to drop the file in app/helpers since it is a helper, after all.

Internationalizing whole text with markup in Rails 3

What's the best practice for internationalizing, say, a Terms of Service document in Rails 3? I can think of two options:
Creating a partial for each locale and choosing which one to load according to the current user's locale.
<li><%= I18n.t :tos_paragraph_1 %></li><li><%= I18n.t :tos_paragraph_2 %></li>
None of these seems like a good solution. Any ideas?
There are a few solutions, but if I were doing this for a production project, I would probably do something like the following:
Create files for your translated Terms of Services in config/locales/terms/, naming them terms.en.html, replacing en with the locale for each translation and html with the format of the file (e.g. you could use Haml, Markdown, etc.).
Create the following helper methods (put them in app/helpers/application_helper.rb to use them everywhere, but you can put them in whatever helper file you need/want):
def localized_document_for(document, locale)
raise ArgumentError.new('nil is not a valid document') if document.nil?
raise I18n::InvalidLocale.new('nil is not a valid locale') if locale.nil?
localized_document = path_for_localized_document(document, locale)
raise MissingTranslationData unless File.exists?(localized_document)
# If you're using Markdown, etc. replace with code to parse/format your document
File.open(localized_document).readlines.join
end
def path_for_localized_document(document, locale)
"#{Rails.root}/config/locales/#{document}/#{document}.#{locale.to_s}.html"
end
Now, in your views, you can use localized_document_for('terms', I18n.locale) any time you need to get the contents of the Terms of Service in the user's language. Now the code you're using to fetch the document is DRY (you can easily fetch other documents by creating another directory in config/locales and changing the value of the document argument), and your translated documents are stored in their own directory and can easily be edited (and don't depend on YAML, which brings no value to storing a single document in a file).
Note that if you wanted to do it the "Rails 3 Way," you could use the I18n::Backend::Chain (see https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/chain.rb), and pass in I18n::Backend::Simple.new along with a custom backend that reads the files as necessary, but for a one-off deal I believe the helpers work sufficiently.
Creating a partial for each language is definitly undry.
The Rails way is the second option you suggest with a .yml for each language.
The doc provides great examples to let you organize the yml according to each page. Thus you have shortcuts for all your variables.
See http://guides.rubyonrails.org/i18n.html

Most appropriate way to generate directory of files from directory of template files with Rails and ERB?

My goal is to generate a directory of static html, javascript, and image files within my Rails (3) app, driven by ERB templates. For example, as a developer I might want to generate/update these files:
#{Rails.root}/public/products/baseball.html
#{Rails.root}/public/products/football.js
..from the following template files:
#{Rails.root}/product_templates/baseball.html.erb
#{Rails.root}/product_templates/football.js.erb
Ideally the templates would have access to my app's Rails environment (including URL helpers, view helpers, partials, etc.).
What's the latest and greatest way to accomplish this?
I experimented with a custom Rails generator, but found that I needed to write custom logic for skipping non-ERB files, substituting file names, etc. There must be a better way.
I'm not sure what you are trying to do exactly, that may help provide better answers, but here is some useful information:
You can call into erb directly, some information on that is here, which have probably already been doing:
http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
For the list of template files an easy Dir.glob should be able to help find the specific files easily and loop through them:
http://ruby-doc.org/core/classes/Dir.html#M000629
The tricky part I wouldn't know how to advise you on is getting access to the helpers and other things Rails provides. The helpers that you write are just modules, so you could mix those in, something similar might be possible with the built-in rails helpers.
This is interesting and related but doesn't directly answer your question, since its uses the Liquid templating engine instead of ERB, but otherwise, it does some of the static site generation you are talking about:
https://github.com/mojombo/jekyll
This is how I accomplished something similar. It accepts source and destination directories, wipes out the destination, then processes the source directory, either ERB-processing files and placing them in the destination or simply copying them (in the case of on-ERB files). It would need to be modified to handle recursively processing a directory.
I invoke it from a rake task like so:
DirectoryGenerator.new.generate(Rails.root.join('src'), Rails.root.join('public', 'dest'))
class DirectoryGenerator
include Rails.application.routes.url_helpers
include ActionView::Helpers::TagHelper
default_url_options[:host] = 'www.example.com'
def generate(source, destination)
FileUtils.rmtree(destination)
FileUtils.mkdir_p(destination)
Dir.glob(File.join(source, '*')).each do |path|
pathname = Pathname.new(path)
if pathname.extname == '.erb'
File.open(destination.join(pathname.basename.sub(/\.erb$/, '')), 'w') do |file|
file.puts(ERB.new(File.read(path)).result(binding))
end
else
FileUtils.cp(pathname, File.join(destination, pathname.basename))
end
end
end
end
Have you looked into Rails templates?
http://m.onkey.org/rails-templates for instance..
Not sure what you are getting at exactly.. are you trying to generate client sites by providing a few parameters.. that the end goal?

Resources