It's possible to write Markdown content with invalid syntax. Invalid means that the BlueCloth library fails to parse the content and throws an exception. The markdown helper in Rails doesn't catch any BlueCloth exceptions and because of that the complete page fails to render (500 Server Error page is rendered instead).
In my case, users are allowed to write Markdown content and save it to the database. If someone used invalid syntax, all successive rendering attempts of that content fail (Status Code 500 - Internal Server Error).
How do you get around this issue? Is it possible to validate the Markdown syntax at the Model-level before saving to the database?
You should write your own validation method in which you would initialize BlueCloth object, and try to call to_html method catching any exception. If you catch an exception, validation fails, otherwise it should be ok.
In your model:
protected:
def validate
bc = BlueCloth.new(your_markdown_string_attribute)
begin
bc.to_html
rescue
errors.add(:your_markdown_string_attribute, 'has invalid markdown syntax')
end
end
I've done a bit of research and decided to use RDiscount instead of BlueCloth. RDiscount seems to be much faster and more reliable than BlueCloth.
It's easy to integrate RDiscount in your Rails environment. Include the following snipped in your environment.rb and you are ready to go:
begin
require "rdiscount"
BlueCloth = RDiscount
rescue LoadError
# BlueCloth is still the our fallback,
# if RDiscount is not available
require 'bluecloth'
end
(tested with Rails 2.2.0)
Related
I've got some Rspec tests that I'm using to test a module. The module is used by a number of models in my Rails app. In order to keep testing time down to a minimum, I want to avoid loading Rails when testing my module.
The problem is that there are a few methods that contain rescues and those rescues mention the Rails debugger. When Rspec sees the capital 'r' in Rails, it has a bad time because it considers it an uninitialized constant.
I was hoping that if I wrapped up the logging info into its own method, I could avoid the problem. Here's what I came up with. But if I go down this road, I would need to stub either the rescue code or or the log_info method. Is that right? How would I do that? And which one should I stub?
def download_robots_file(page)
file = Net::HTTP.get(URI("#{page}robots.txt"))
rescue StandardError => ex
log_info('robot_file', ex)
end
....
private
def log_info(problem, exception_issue)
Rails.logger.debug("Couldn't download #{problem}: " + exception_issue.inspect)
end
You can add to stub chain method that you want to stub.
Rails.stub_chain(:logger).and_return(mocked_logger_instance)
Un-stub in the end with:
Rails.unstub(:logger)
All credits go to mister on following link How to rspec mock ruby rails logger class
I am using Omniauth for Rails 3.2.3 application.
I have configured the on_failure callback as show below.
OmniAuth.config.on_failure = Proc.new do |env|
UsersController.action(:omniauth_failure).call(env)
end
This handles the error "OmniAuth::Strategies::CallbackError" but not "OmniAuth::Strategies::Facebook::NoAuthorizationCodeError".
How to handle this error?.Surly I can not use rescue_from as the error happens in Rack level.
Any ideas?
Thank you
Ensure that your Facebook Application is not running in "Sandbox Mode"
I've run into the same issue.
By my humble investigation it seems to be a bug in the strategy implemented in the omniauth-facebook gem (and, at a quick glance in several others). This is a nice write-up on exception handling in omniauth. It says that
... OmniAuth strategies [...], if they encounter a problem, call the method fail! and pass in a symbol describing the problem like :invalid_credentials and the exception they encountered. The fail! method ends up calling OmniAuth.config.on_failure and passing in the Rack environment (after doing a few other things like sticking the exception into the environment...
The same can be inferred from an example the original authors kindly provided. In the source it's not emphasized and I haven't found it in the wiki docs, either (but I may have overlooked).
Many strategies, including omniauth-facebook, currently raises the exception which we cannot catch at app level anymore.
#soundar: I wish that it worked this way, as advertised.
#fastcatch: As you pointed out, the strategies are not handling these failure cases correctly.
#Jon Day: I had to patch the Rack App for 'omniauth-facebook' (1.4.0) in order to get the reporting that I needed:
require 'newrelic_rpm'
module OmniAuth
class Builder < ::Rack::Builder
def call_with_error_handling(env)
begin
call_without_error_handling(env)
rescue OmniAuth::Strategies::Facebook::NoAuthorizationCodeError => error
# Do whatever you'd like when rescuing.. I wanted to report to NewRelic.
NewRelic::Agent.notice_error(error, env)
env
end
end
alias_method_chain :call, :error_handling
end
end
I'm not proud of this code, but it is one way to gain control over that exception ;).
I am trying to generate a resource and I have removed all references to Active_record and removed the databse.yml file.
The rails server starts ok but when I try to generate a model:
rails g resource contact
I get the following error:
No value provided for required options '--orm'
Is there a way to specify no database when generating a resource?
There isn't an easy way, no. If you look at the source code for the resource generator, you'll see this part regarding the orm:
# Loads the ORM::Generators::ActiveModel class. This class is responsible
# to tell scaffold entities how to generate an specific method for the
# ORM. Check Rails::Generators::ActiveModel for more information.
def orm_class
#orm_class ||= begin
# Raise an error if the class_option :orm was not defined.
unless self.class.class_options[:orm]
raise "You need to have :orm as class option to invoke orm_class and orm_instance"
end
begin
"#{options[:orm].to_s.camelize}::Generators::ActiveModel".constantize
rescue NameError
Rails::Generators::ActiveModel
end
end
end
So it explicitly rejects any attempt to run this command without an ORM, and if you do specify an ORM, it's looking for ORM::Generators::ActiveModel. And in the comments at the top, it specifies a location to find more information, Rails::Generators::ActiveModel. The comments at the top there explain how to extend it to create an ORM specification.
The only one built-in to rails by default is the ActiveRecord generator.
There is a gem called rails3-generators that includes generators for a number of common libraries, but you can see that for ORMs it only adds functionality for data_mapper, mongo_mapper, mongoid, and active_model.
As far as I know, there is no pre-built ORM generator for "no database". You could write one yourself, if you want, by following the instructions at the top of Rails::Generators::ActiveModel (and using the rails3-generators gem source as a reference of you need it).
But if that seems like too much effort, I'd recommend just telling it to generate using the built-in ActiveRecord generator, and then just manually modifying/removing anything it generated related to that ORM.
Our team is working on a new application that we started with Rails 3.1 and Ruby 1.9.2 - and last night I took it to Ruby 1.9.3.
One of the gems we were using in the dependency chain (css_parser) ended up having a require 'iconv' in it, triggering a deprecation warning in 1.9.3 that looked like this:
.../gems/activesupport-3.1.1/lib/active_support/dependencies.rb:240:in `block in require': iconv will be deprecated in the future, use String#encode instead.
At first I naively blamed that on rails without a better trace, until I didn't find a require 'iconv' in it anywhere.
The only way I tracked this down was that I started commenting things out in my Gemfile and then I finally got the bright idea to load irb and start requiring each library in turn. I also could have just done a filesystem grep in the gems directory, but I wasn't exactly sure that "require 'iconv'" was what was triggering the error.
What a PITA. There has to be a better way - just doing a --trace in rake tasks that load rails didn't cut it. Is there some way / any way of triggering a trace on this that would have shown me which line in the relatively long list of library dependencies was triggering the deprecation?
So, it's probably a little moot because I'm not likely to ever run into the problem again (and the css_parser gem was the only iconv-requiring gems in my current Rails 3.1/Ruby 1.9.3 projects).
But it was a puzzle, so I wanted to find some way of solving it.
The problem is very iconv-specific in this case. There are other ruby deprecations, but for the most part they seem to go through Kernel#warn (if ruby) or rb_warn() (if C) - but the warning in iconv.c is a little different than the others - at any rate it's a puts to rb_stderr.
So maybe I can do the following
Override Kernel#require to capture stderr
Check for an iconv message after calling the original Kernel#require
Raise an exception if the message found, thereby getting a trace
Do this before bundler runs if at all possible.
It turns out I can't do #4 - because Bundler calls Kernel.require directly - but I can use Bundler to parse the Gemfile to give me a list of things to require myself.
So this is what I get - thanks to this stack overflow post for a pointer on capturing standard error - and the rubygems source for the idea on aliasing the original Kernel#require
# override Kernel#require to intercept stderr messages on require
# and raise a custom error if we find one mentioning 'iconv'
require "stringio"
class RequireError < StandardError
end
module Kernel
alias :the_original_require require
private :the_original_require
def capture_stderr
# The output stream must be an IO-like object. In this case we capture it in
# an in-memory IO object so we can return the string value. You can assign any
# IO object here.
previous_stderr, $stderr = $stderr, StringIO.new
yield
$stderr.string
ensure
# Restore the previous value of stderr (typically equal to STDERR).
$stderr = previous_stderr
end
def require(name)
captured_output = capture_stderr do
the_original_require(name)
end
if(captured_output =~ %r{iconv})
raise RequireError, 'iconv requirement found'
end
end
end
require 'bundler'
# load the list of Bundler requirements from the Gemfile
required_libraries = Bundler.definition.dependencies.map(&:name)
# loop through and require each, ignoring all errors other than
# our custom error
required_libraries.each do |requirement|
begin
require(requirement)
rescue Exception => e
if(e.class == RequireError)
raise e
end
end
end
And voila! A trace message that helps track down where the iconv requirement was.
In the end, probably just a search for "require 'iconv'" is still best (once it's clear that's the what was causing the error).
But, as in life. Some Yaks Must Be Shaved.
You could take a look at the Gemfile.lock file, which holds all dependencies in a hierarchical tree and indicates the versions required by each gem. This might help to identify the gem that is requiring it.
I have activemerchant 1.16.0 and rails 3.0.5.
I am trying to build a basic code to communicate with PayPal's gateway using active merchant.
if credit_card.valid?
# or gateway.purchase to do both authorize and capture
response = gateway.authorize(1000, credit_card, :ip => "127.0.0.1")
if response.success?
gateway.capture(1000, response.authorization)
puts "Purchase complete!"
else
puts "Error: #{response.message}"
end
else
puts "Error: credit card is not valid. #{credit_card.errors.full_messages.join('. ')}"
end
I get the following error:
/Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/xml_mini/rexml.rb:20:in `parse': uninitialized constant ActiveSupport::XmlMini_REXML::StringIO (NameError)
This error propagates from the gateway.authorize() call.
Any idea what's wrong with my setup?
Thanks.
According to the question, it doesn't work when the code is by itself, but works when require "stringio" is added.
My suspicion is that ActiveMerchant is unit-tested, but for some reason the dependency on StringIO isn't detected by those unit tests, possibly because other parts of the unit testing code indirectly requires stringio.
One thing I recently found out was that require 'yaml' gives you the stringio library as a side effect:
StringIO.new
# NameError: uninitialized constant StringIO
# from (irb):1
require "yaml"
# => true
StringIO.new
# => #<StringIO:0x7fb7d48ce360>
RUBY_VERSION
# => "1.8.7"
and it wouldn't be hard to imagine unit tests for ActiveMerchant (or other parts of Rails) requiring yaml.
However, this is only speculation. I haven't checked, as I don't use Rails.
Andrew Grimm pretty much hit the nail on the head with his original comment on this question. The missing require 'stringio' is indeed the issue. But it is a bug with Rails, more specifically ActiveSupport 3.0.9 (which is where the error seems to be coming from). We can trace it down using the git commit history of rails.
First we need to check out rails and switch to the v3.0.9 tag. If we now look at activesupport/lib/active_support/xml_mini/rexml.rb we see that require 'stringio' is not there. In and of itself this is not significant, but bear with me. We can now switch to the next tag (v3.0.10.rc1), and we'll see that the file hasn't been updated (it is likely that this version of rails will have the same issue). Next tag in line is v3.1.0.beta1, notice that this time around there is a require 'stringio' at the top of the file.
We can check out the commit that brought in this change (this one here from Jan 19th 2011). The commit message says:
fixed a missing require that causes trouble when using AS in a
non-rails env
This would indicate that as long as you're in a rails environment this issue wouldn't surface. So, my guess is something about the environment caused the issue to come up, may have something to do with the fact that the OP says they are using rails 3.0.5, but the error is coming from activesupport-3.0.9. Perhaps the code was called from a rake task that forgot to inherit from :environment (difficult to say without more info). Either way, putting require 'stringio' at the top of the code is definitely the fix, until you can upgrade to Rails 3.1 (once it comes out) at which point the require will no longer be needed.