Override Rack method - ruby-on-rails-3

My setup: Rails 3.0.9, Ruby 1.9.2
Due to a bug in Rack 1.2.3, I'm attempting to override Rack::Utils::Multipart.parse_multipart by creating a new file
rack_parse_multipart.rb
module Rack
module Utils
module Multipart
def self.parse_multipart(env)
...my changes...
end
end
end
end
Now I just need to figure out where I require this file, can someone point me in the right direction? Thanks in advance for your help.

For others having problems with this Rack 1.2.3 bug, there is a nice copy-paste solution here https://github.com/rack/rack/issues/186
goes in config/initializers
# -*- encoding: binary -*-
require 'rack/utils'
module Rack
module Utils
module Multipart
def self.parse_multipart(env)
unless env['CONTENT_TYPE'] =~
%r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
nil
else
boundary = "--#{$1}"
params = {}
buf = ""
content_length = env['CONTENT_LENGTH'].to_i
input = env['rack.input']
input.rewind
boundary_size = Utils.bytesize(boundary) + EOL.size
bufsize = 16384
content_length -= boundary_size
read_buffer = ''
status = input.read(boundary_size, read_buffer)
raise EOFError, "bad content body" unless status == boundary + EOL
rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
loop {
head = nil
body = ''
filename = content_type = name = nil
until head && buf =~ rx
if !head && i = buf.index(EOL+EOL)
head = buf.slice!(0, i+2) # First \r\n
buf.slice!(0, 2) # Second \r\n
token = /[^\s()<>,;:\\"\/\[\]?=]+/
condisp = /Content-Disposition:\s*#{token}\s*/i
dispparm = /;\s*(#{token})=("(?:\\"|[^"])*"|#{token})*/
rfc2183 = /^#{condisp}(#{dispparm})+$/i
broken_quoted = /^#{condisp}.*;\sfilename="(.*?)"(?:\s*$|\s*;\s*#{token}=)/i
broken_unquoted = /^#{condisp}.*;\sfilename=(#{token})/i
if head =~ rfc2183
filename = Hash[head.scan(dispparm)]['filename']
filename = $1 if filename and filename =~ /^"(.*)"$/
elsif head =~ broken_quoted
filename = $1
elsif head =~ broken_unquoted
filename = $1
end
if filename && filename !~ /\\[^\\"]/
filename = Utils.unescape(filename).gsub(/\\(.)/, '\1')
end
content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
if filename
body = Tempfile.new("RackMultipart")
body.binmode if body.respond_to?(:binmode)
end
next
end
# Save the read body part.
if head && (boundary_size+4 < buf.size)
body << buf.slice!(0, buf.size - (boundary_size+4))
end
c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
raise EOFError, "bad content body" if c.nil? || c.empty?
buf << c
content_length -= c.size
end
# Save the rest.
if i = buf.index(rx)
body << buf.slice!(0, i)
buf.slice!(0, boundary_size+2)
content_length = -1 if $1 == "--"
end
if filename == ""
# filename is blank which means no file has been selected
data = nil
elsif filename
body.rewind
# Take the basename of the upload's original filename.
# This handles the full Windows paths given by Internet Explorer
# (and perhaps other broken user agents) without affecting
# those which give the lone filename.
filename = filename.split(/[\/\\]/).last
data = {:filename => filename, :type => content_type,
:name => name, :tempfile => body, :head => head}
# elsif !filename && content_type
# body.rewind
#
# # Generic multipart cases, not coming from a form
# data = {:type => content_type,
# :name => name, :tempfile => body, :head => head}
else
data = body
end
Utils.normalize_params(params, name, data) unless data.nil?
# break if we're at the end of a buffer, but not if it is the end of a field
break if (buf.empty? && $1 != EOL) || content_length == -1
}
input.rewind
params
end
end
end
end
end

Don't do it like this, your file should be like this:
Rack::Utils::UploadedFile.class_eval do
def self.parse_multipart( env )
# add your code here
end
end
This file can be placed in a initializer file on your initializers folder.
The difference between doing the way you did and the way I'm showing is that when you're using module/class you might break the Rails autoload mechanism, as Rails could think you're defining the class (and not load the original class by itself) and the original class would never be loaded.
Whenever you're doing monkey patching like this make sure you use the class_eval solution so that Rails is forced to load the original class first and then runs your code.

Related

NameError (uninitialized constant Twitter::TextExtractor):

I am getting error while using Twitter-text gem.
I am getting -> NameError (uninitialized constant Twitter::TextExtractor) while creating entry.
here is the right code below
class EntryParser
class << self
include Twitter::Extractor
# Default CSS class for auto-linked lists
DEFAULT_LIST_CLASS = "url link-list-slug".freeze
# Default CSS class for auto-linked usernames
DEFAULT_USERNAME_CLASS = "url link-username".freeze
# Default CSS class for auto-linked hashtags
DEFAULT_HASHTAG_CLASS = "url link-hashtag".freeze
# Default CSS class for auto-linked cashtags
DEFAULT_CASHTAG_CLASS = "url link-cashtag".freeze
# Default URL base for auto-linked usernames
DEFAULT_USERNAME_URL_BASE = "/users/".freeze
# Default URL base for auto-linked lists
DEFAULT_LIST_URL_BASE = "/users".freeze
# Default URL base for auto-linked hashtags
DEFAULT_HASHTAG_URL_BASE = "/tags/".freeze
# Default URL base for auto-linked cashtags
DEFAULT_CASHTAG_URL_BASE = "#!tag?q=%24".freeze
# Default attributes for invisible span tag
DEFAULT_INVISIBLE_TAG_ATTRS = "style='position:absolute;left:-9999px;'".freeze
DEFAULT_OPTIONS = {
:list_class => DEFAULT_LIST_CLASS,
:username_class => DEFAULT_USERNAME_CLASS,
:hashtag_class => DEFAULT_HASHTAG_CLASS,
:cashtag_class => DEFAULT_CASHTAG_CLASS,
:username_url_base => DEFAULT_USERNAME_URL_BASE,
:list_url_base => DEFAULT_LIST_URL_BASE,
:hashtag_url_base => DEFAULT_HASHTAG_URL_BASE,
:cashtag_url_base => DEFAULT_CASHTAG_URL_BASE,
:invisible_tag_attrs => DEFAULT_INVISIBLE_TAG_ATTRS
}.freeze
def parse(entry)
sanitizer = Rails::Html::FullSanitizer.new
sanitized = sanitizer.sanitize(entry.body.gsub(/^(\[[\sx]*)\]/, ''))
sanitized.gsub("\n", "<br/>")
end
# Produces an HTML output string with all of the parsed links we want
def auto_link(entry)
parsed = parse(entry)
entities = extract_entities(parsed)
auto_link_entities_wthout_cmmnt(entry, parsed, entities)
end
def auto_link_comment(reaction) # should probably live in a CommentParser
# This will break if we allow comments on comments, then we need to rethink how
# we do this
if reaction.reaction_type == 'comment' && reaction.reactable.class == Entry
sanitizer = Rails::Html::FullSanitizer.new
sanitized = sanitizer.sanitize(reaction.body)
entities = extract_entities(sanitized)
auto_link_entities(reaction.reactable, reaction, sanitized, entities)
else
reaction.body
end
end
def auto_link_entities_wthout_cmmnt(entry, text, entities)
return text if entities.empty?
# TODO: This is likely inefficient, needs caching or preloading
if entry.team.personal?
org_hash = nil
personal = true
else
org_hash = entry.team.organization.hash_id
personal = false
end
Twitter::Rewriter.rewrite_entities(text.dup, entities) do |entity, _chars|
if entity[:url]
image_or_link(entity[:url])
elsif entity[:hashtag]
if personal
"##{entity[:hashtag]}"
else
"##{entity[:hashtag]}"
end
elsif entity[:screen_name]
if !personal && user = entry.team.active_users.where(go_by_name: entity[:screen_name]).first
"##{entity[:screen_name]}"
else
"##{entity[:screen_name]}"
end
end
end
end
def auto_link_entities(entry,comment , text, entities)
return text if entities.empty?
# TODO: This is likely inefficient, needs caching or preloading
if entry.team.personal?
org_hash = nil
personal = true
else
org_hash = entry.team.organization.hash_id
personal = false
end
Twitter::Rewriter.rewrite_entities(text.dup, entities) do |entity, _chars|
if entity[:url]
image_or_link(entity[:url])
elsif entity[:hashtag]
if personal
"##{entity[:hashtag]}"
else
if comment
"##{entity[:hashtag]}"
else
"##{entity[:hashtag]}"
end
end
elsif entity[:screen_name]
if !personal && user = entry.team.active_users.where(go_by_name: entity[:screen_name]).first
"##{entity[:screen_name]}"
else
"##{entity[:screen_name]}"
end
end
end
end
# This is overridden from Twitter::Extractor because we don't want cashtags
def extract_entities(text, &block)
entities = extract_urls_with_indices(text, {extract_url_without_protocol: true}) +
extract_hashtags_with_indices(text, :check_url_overlap => false) +
extract_mentions_or_lists_with_indices(text)
return [] if entities.empty?
entities = remove_overlapping_entities(entities)
entities.each(&block) if block_given?
entities
end
def image_or_link(entity_link)
entity_url = entity_link.length > 30 ? "#{entity_link[0,25]}..." : entity_link
page_path = Addressable::URI.heuristic_parse(entity_link).to_s
begin
if ['.jpg','.png', '.gif', '.jpeg'].any? { |image_ext| page_path.downcase.include?(image_ext) }
"#{entity_url}
<div class='entry-img'>
<img src='#{page_path}' style='max-width:266px; max-height:200px;'>
</div>"
else
"#{entity_url}"
end
rescue
"#{entity_url}"
end
end
end
end
I don't know what is problem here.

Needs redirects for routing

I'm very excited about Camaleon cms for rails 5; however, I've noticed a significant problem with posts that have parent slugs or have post-type slugs in the url as a url format.
For background, it's very important that a post's content can only be reached via one single url. Otherwise, you have the potential for getting penalized in google for having duplicate content. For those who rely on search engine traffic (basically everyone who would ever use a CMS), this is a very serious issue.
The following is an example of the issue. All of these urls will render the same post content:
http://www.example.com/parent_slug/post_slug
http://www.example.com/post_slug
http://www.example.com/parent_slug_blah_blah/post_slug
Or
http://www.example.com/post_type/post_slug
http://www.example.com/post_slug
http://www.example.com/post_type_blah_blah/post_slug
The way Wordpress deals with this issue is to redirect to the proper url with the correct parent slug if it doesn't exist or if it is misspelled.
My question here is for those in the know, is this perhaps a priority issue in one of the upcoming releases?
I'm not sure if this will work for everyone, but here's my solution to this issue.
Requirements: this will only work for posts that have the "post_of_posttype", "heirarchy_post" or "post_of_category_post_type" route formats.
The following code is extending the functionality of Camaleon's frontend controller method render_post by simply adding a redirect when the params don't match the #post.the_path. Seems to work for my purposes. Hopefully it will help someone else.
Create a new file in your config/initializers folder and place the following code:
# config/initializers/camaleon_custom_post.rb
CamaleonCms::FrontendController.class_eval do
# render a post
# post_or_slug_or_id: slug_post | id post | post object
# from_url: true/false => true (true, permit eval hooks "on_render_post")
def render_post(post_or_slug_or_id, from_url = false, status = nil)
if post_or_slug_or_id.is_a?(String) # slug
#post = current_site.the_posts.find_by_slug(post_or_slug_or_id)
elsif post_or_slug_or_id.is_a?(Integer) # id
#post = current_site.the_posts.where(id: post_or_slug_or_id).first
else # model
#post = post_or_slug_or_id
end
unless #post.present?
if params[:format] == 'html' || !params[:format].present?
page_not_found()
else
head 404
end
else
#post = #post.decorate
if ["post_of_posttype","hierarchy_post"].include? #post.the_post_type.contents_route_format
if params[:parent_title].nil? && params[:post_type_title].nil?
params_path = "/" + params[:slug]
elsif !params[:parent_title].nil?
params_path = "/" + params[:parent_title] + "/" + params[:slug]
elsif !params[:post_type_title].nil?
params_path = "/" + params[:post_type_title] + "/" + params[:slug]
end
unless (#post.the_path === params_path)
redirect_to #post.the_url, status: 301 and return
end
elsif #post.the_post_type.contents_route_format === "post_of_category_post_type"
if [params[:post_type_title],params[:label_cat],params[:category_id],params[:title]].all?
params_path = [params[:post_type_title],params[:label_cat],params[:category_id] + "-" + params[:title],params[:slug]].join("/")
params_path.prepend("/")
unless (#post.the_path === params_path)
redirect_to #post.the_url, status: 301 and return
end
else
redirect_to #post.the_url, status: 301 and return
end
end
#object = #post
#cama_visited_post = #post
#post_type = #post.the_post_type
#comments = #post.the_comments
#categories = #post.the_categories
#post.increment_visits!
# todo: can_visit? if not redirect home page
home_page = #_site_options[:home_page] rescue nil
if lookup_context.template_exists?("page_#{#post.id}")
r_file = "page_#{#post.id}"
elsif #post.get_template(#post_type).present? && lookup_context.template_exists?(#post.get_template(#post_type))
r_file = #post.get_template(#post_type)
elsif home_page.present? && #post.id.to_s == home_page
r_file = "index"
elsif lookup_context.template_exists?("post_types/#{#post_type.the_slug}/single")
r_file = "post_types/#{#post_type.the_slug}/single"
elsif lookup_context.template_exists?("#{#post_type.slug}")
r_file = "#{#post_type.slug}"
else
r_file = "single"
end
layout_ = nil
meta_layout = #post.get_layout(#post_type)
layout_ = meta_layout if meta_layout.present? && lookup_context.template_exists?("layouts/#{meta_layout}")
r = {post: #post, post_type: #post_type, layout: layout_, render: r_file}
hooks_run("on_render_post", r) if from_url
if status.present?
render r[:render], (!r[:layout].nil? ? {layout: r[:layout], status: status} : {status: status})
else
render r[:render], (!r[:layout].nil? ? {layout: r[:layout]} : {})
end
end
end
end
Seems kind of strange the mandatory redirect for non-accurate urls is not in the core camaleon application, but perhaps most people who use this cms are creating internally facing apps. Anyway, if that's not the case, I think this should be a priority fix.

Helper methods available in mailer views depend on environment?

Related to my previous question I still have one thing that I would like to understand - why this:
= link_to(root_path)
= link_to(#some_path_set_in_mailer)
works in development mode (config.action_mailer.perform_deliveries was set to true and emails were actually sent) and in production or staging has to be changed to:
= link_to(#some_path_set_in_mailer, #some_path_set_in_mailer)
to avoid "No route matches {}" error?
I had this problem in rails 3.2.
I'm not entirely sure why there is a difference since there shouldn't be.
However, link_to typically has this format:
= link_to("Some link description here", root_path)
The only time you typically leave off the link description text is if you have a longer description that you need to put within a do block like this:
= link_to(root_path) do
%p Some link description here
= image_tag("some_image.jpg")
So I would recommend sticking to the preferred syntaxes above.
The docs for link_to don't really talk about the short-hand method you're using too much.
Here is the source for it:
# File actionpack/lib/action_view/helpers/url_helper.rb, line 231
def link_to(*args, &block)
if block_given?
options = args.first || {}
html_options = args.second
link_to(capture(&block), options, html_options)
else
name = args[0]
# this is probably where your issue is coming from
options = args[1] || {}
html_options = args[2]
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
href = html_options['href']
tag_options = tag_options(html_options)
href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
"<a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a>".html_safe
end
end

use base64 image with Carrierwave

I want to perform the similar thing as from base64 photo and paperclip -Rails, but with Carrierwave.
Could anybody explain me using of base64 images in Carrierwave?
class ImageUploader < CarrierWave::Uploader::Base
class FilelessIO < StringIO
attr_accessor :original_filename
attr_accessor :content_type
end
before :cache, :convert_base64
def convert_base64(file)
if file.respond_to?(:original_filename) &&
file.original_filename.match(/^base64:/)
fname = file.original_filename.gsub(/^base64:/, '')
ctype = file.content_type
decoded = Base64.decode64(file.read)
file.file.tempfile.close!
decoded = FilelessIO.new(decoded)
decoded.original_filename = fname
decoded.content_type = ctype
file.__send__ :file=, decoded
end
file
end
The accepted answer did not worked for me (v0.9).
It seems to be a check that fails before the cache callback.
This implementation works:
class ImageUploader < CarrierWave::Uploader::Base
# Mimick an UploadedFile.
class FilelessIO < StringIO
attr_accessor :original_filename
attr_accessor :content_type
end
# Param must be a hash with to 'base64_contents' and 'filename'.
def cache!(file)
if file.respond_to?(:has_key?) && file.has_key?(:base64_contents) && file.has_key?(:filename)
local_file = FilelessIO.new(Base64.decode64(file[:base64_contents]))
local_file.original_filename = file[:filename]
extension = File.extname(file[:filename])[1..-1]
local_file.content_type = Mime::Type.lookup_by_extension(extension).to_s
super(local_file)
else
super(file)
end
end
end

How can I load data into database using activerecord

I have a ruby script that extracts information from a file (genbank) and I would like to load this data into the database. I have created the model and the schema and a connection script:
require 'active_record'
def establish_connection(db_location= "protein.db.sqlite3")
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database => db_location,
:pool => 5,
:timeout => 5000
)
end
This is my script that outputs the data:
require 'rubygems'
require 'bio'
require 'snp_db_models'
establish_connection
snp_positions_file = File.open("snp_position.txt")
outfile = File.open("output.txt", "w")
genome_sequence = Bio::FlatFile.open(Bio::EMBL, "ref.embl").next_entry
snp_positions = Array.new
snp_positions_file.gets # header line
while line = snp_positions_file.gets
snp_details = line.chomp.split("\t")
snp_seq = snp_details[1]
snp_positions << snp_details[1].to_i
end
mean_snp_per_base = snp_positions.size/genome_sequence.sequence_length.to_f
puts "Mean snps per base: #{mean_snp_per_base}"
#outfile = File.open("/Volumes/DataRAID/Projects/GAS/fastq_files/bowtie_results/snp_annotation/genes_with_higher_snps.tsv", "w")
outfile.puts("CDS start\tCDS end\tStrand\tGene\tLocus_tag\tnote\tsnp_ID\ttranslation_seq\tProduct\tNo_of_snps_per_gene\tsnp_rate_vs_mean")
genome_sequence.features do |feature|
if feature.feature !~ /gene/i && feature.feature !~ /source/i
start_pos = feature.locations.locations.first.from
end_pos = feature.locations.locations.first.to
number_of_snps_in_gene = (snp_positions & (start_pos..end_pos).to_a).size # intersect finds number of times snp occurs within cds location
mean_snp_per_base_in_gene = number_of_snps_in_gene.to_f/(end_pos - start_pos)
outfile.print "#{start_pos}\t"
outfile.print "#{end_pos}\t"
if feature.locations.locations.first.strand == 1
outfile.print "forward\t"
else
outfile.print "reverse\t"
end
qualifiers = feature.to_hash
["gene", "locus_tag", "note", "snp_id", "translation", "product"].each do |qualifier|
if qualifiers.has_key?(qualifier) # if there is gene and product in the file
# puts "#{qualifier}: #{qualifiers[qualifier]}"
outfile.print "#{qualifiers[qualifier].join(",")}\t"
else
outfile.print " \t"
end
end
outfile.print "#{number_of_snps_in_gene}\t"
outfile.print "%.2f" % (mean_snp_per_base_in_gene/mean_snp_per_base)
outfile.puts
end
end
outfile.close
How can I load the data in outfile.txt into the database. Do I have to do something like marshall dump?
Thanks in advance
Mark
Your can write a rake task to do this. Save it in lib/tasks and give it a .rake extension.
desc "rake task to load data into db"
task :load_data_db => :environment do
...
end
Since the rails environment is loaded, you can access your Model directly as you would in any Rails model/controller. Of course, it'll connect to the database depending on the environment variable defined when you execute your rake task.
In a mere script, your models are unknown.
You have to define a minimum to use them as if in a Rails App. Simply declare them:
class Foo << ActiveRecord:Base
end
Otherwise, in a Rails context, use rake tasks which are aware of the Rails app details.