how to append/replace alt/title attribute in all image tags? - ruby-on-rails-3

say I have an action template like this
# home/index.html.erb
<%= img_tag "logo.gif" %>
if I want to add alt/title attribute to it, I can just do
# home/index.html.erb
<%= img_tag "logo.gif", alt: "alt!!", title: "title!!" %>
but I have 1000 image tags and I don't want to change every each one of them.
I then thought of using rack middleware and modify image tags before outputting from server.
http://railscasts.com/episodes/151-rack-middleware?view=asciicast
doc = Nokogiri.HTML(#response.body)
doc.search("img").each do |tag|
[:alt, :title].each{|attribute| tag[attribute] = "changed!!" }
end
but when I follow the railscast episode, it appends entire body on the top of the original rather than replacing it.
Am I doing it wrong in the rack, or is there a smarter way to do this?

Updated answer:
# /config/initializers/image_tag_helper.rb
module ActionView
module Helpers
module AssetTagHelper
def image_tag(source, options={})
options[:src] = path_to_image(source)
options[:alt] = "Default Alt" unless options.has_key?(:alt)
options[:title] = "Default Title" unless options.has_key?(:title)
tag(:img, options)
end
end
end
end
This overrides the image_tag helper method to set default alt and title attributes.

Related

Use translation for submit button

I don't want to use the default
<%= f.submit %>
and have created a helper function for it, which also embeds an icon. The helper function expects a label to put on the newly created button.
I'm calling it like this:
<%= submit_button("icon-plus", I18n.translate("helpers.submit.create")) %>
But now on this text appears on the button:
%{model} toevoegen
Instead of:
Product type toevoegen
If I use the normal submit button then the correct text appears so my yml files are correct. How can I get the correct text to use in the helper?
Helper code:
def submit_button(icon, label)
link_to "javascript:void(0)", :class => 'btn btn-primary', :onclick => "$(this).closest('form').submit()" do
raw('<div class="') + icon + raw(' icon-white"> ') + label +raw('</div>')
end
end
As the I18n guide says, the translate function interpolates variables passed in the %{} brackets using its second argument (a hash).
In your case you need to tell it the model by doing this:
I18n.t("helpers.submit.create", model: "Product type")
If you want a generic option that would work for any model, you can see how Rails itself does it by looking at the source on GitHub - it's something like
I18n.t("helpers.submit.create", model: f.object.class.model_name.human)
As an aside, you don't need to (and probably shouldn't) use raw there. What you are trying to achieve could easily be done with the built-in helpers:
link_to ... do
content_tag :div, label, class: "#{icon} icon-white"
end

Rails 3 Searching HTML Content with Sunspot

I'm storing some HTML content in my database and I would like to be able to perform a search using Sunspot while omitting HTML from the hit output and if possible the search itself.
My model:
class Article < ActiveRecord::Base
attr_accessible :caption
searchable do
text :content, :stored => true
end
end
Search action:
def find
#search = Article.search do
fulltext params[:search] do
highlight :name
end
end
end
Template:
- #search.each_hit_with_result do |hit, article|
- unless hit.highlight(:content).nil?
%p= hit.highlight(:content).format { |word| "<span class=\"highlight\">#{strip_tags(word)}</span>"}.html_safe
Some sample content that is being search might be something like:
<h1>Hello world</h1>
<p> Search for me me!</p>
Link
Notice that I'm marking the output as html_safe? This is because I would like the wrap the search text that gets hit with a highlight span, however besides that everything else I want to be stripped completely from the returned text that gets hit. Is this even possible?
What ended up working for me was stripping the content that gets indexed by solr. To do so I had to make the following change inside of my model:
include ActionView::Helpers::SanitizeHelper
searchable do
text :content, :stored => true do
strip_tags(content)
end
end
Adding those changes and running rake sunspot:solr:reindex worked like a charm!

How to get the current view name from layout template in Rails?

Is it possible to get the name of the currently rendered view from inside layout?
I did something like this for css namespacing:
# config/initializers/action_view.rb
ActionView::TemplateRenderer.class_eval do
def render_template_with_tracking(template, layout_name = nil, locals = {})
# with this gsub, we convert a file path /folder1/folder2/subfolder/filename.html.erb to subfolder-filename
#view.instance_variable_set(:#_rendered_template, template.inspect.gsub(/(\..*)/, '').split('/')[-2..-1].join('-'))
out = render_template_without_tracking(template, layout_name, locals)
#view.instance_variable_set(:#_rendered_template, nil)
return out
end
alias_method_chain :render_template, :tracking
end
# application.html.erb
<body class="<%= :#_rendered_template %>" >
Use <% __FILE__ %> to get the complete file path of current view, but you can only use it from within the file itself without writing some helpers
The method active_template_virtual_path method returns the template as a name in the following form "controller/action"
class ActionController::Base
attr_accessor :active_template
def active_template_virtual_path
self.active_template.virtual_path if self.active_template
end
end
class ActionView::TemplateRenderer
alias_method :_render_template_original, :render_template
def render_template(template, layout_name = nil, locals = {})
#view.controller.active_template = template if #view.controller
result = _render_template_original( template, layout_name, locals)
#view.controller.active_template = nil if #view.controller
return result
end
end
I had a similar question. I found <%= params[:controller] %> and <%= params[:action] %> to suit my need, which was to add the controller name and action name as classes on the body tag.
Just in case that helps anyone. :)
I'm currently using a modified version of Peter Ehrlich's solution. The resulting string is of the form controller_name/view_name, e.g. users/new, which means it can be passed directly to render later on, or altered to suit other uses. I've only tried this with Rails 4.2, though as far as I know it ought to work all the way back into the 3.xes.
ActionView::Base.class_eval do
attr_accessor :current_template
end
ActionView::TemplateRenderer.class_eval do
def render_template_with_current_template_accessor(template, layout_name = nil, locals = {})
#view.current_template = template.try(:virtual_path)
render_template_without_current_template_accessor(template, layout_name, locals)
end
alias_method_chain :render_template, :current_template_accessor
end
For debugging purpose, you can use gem 'current_template' from here.
This gem inspects logfile and display file name of view/partial template.
For example:
Also, you can simply add this line
<%= "#{`tail log/development.log`}".scan(/\s[a-z]+\/\S+/) %>
to your layout/application.html.erb.

Rails 3: Will_paginate's .paginate doesn't work

I'm using newes Rails 3 version with will_paginate.
#videos = user.youtube_videos.sort.paginate :page => page
I also added the ##per_page attribute to my youtube_video-model.
But it just won't paginate it. I get always all items in the collection listed.
What have I done wrong?
Yours, Joern.
Why are you calling sort here? That seems unnecessary, and probably would result in it finding all videos and calling pagination on that rather than paying any attention to any variable defined in your Video model. Instead, move the sorting logic into the Video model by using a scope or use the order method.
Here's my solution, my own answer, for all other's having trouble with will_paginate and reading this issue:
Create an ApplicationController method like this:
def paginate_collection(collection, page, per_page)
page_results = WillPaginate::Collection.create(page, per_page, collection.length) do |pager|
pager.replace(collection)
end
collection = collection[(page - 1) * per_page, per_page]
yield collection, page_results
end
Then in your Controller, where you got the collection that should be paginated:
page = setup_page(params[:page]) # see below
#messages = Message.inbox(account)
paginate_collection(#messages, page, Message.per_page) do |collection, page_results|
#messages = collection
#page_results = page_results
end
And in your View:
<% #messages.each do |message| %>
<%# iterate and show message titles or whatever %>
<% end %>
<%= will_paginate #page_results %>
To get the page variable defined, check this:
def setup_page(page)
if !page.nil?
page.to_i
else
1
end
end
So page = setup_page(params[:page]) does the trick, with that simple method.
This WORKS!

Rails 3 Rendering Binary Content

I need to render binary content(images) on web page. I'm saving images in the database with datatype binary. Now I need to iterate available images from the database and render on webpage.
Please check the below code that I'm doing. Icon is the image column name in material.
// iterating all materials
<% #materials.each do |material| %>
// for each material
<span><%= image_tag(material.icon) %></span>
<% end %>
Any help would be greatly appreciated..
You need to add an action to your controller along these lines (cribbed from here):
def image
#material = Material.find(params[:id])
send_data #material.icon, :type => 'image/png',:disposition => 'inline'
end
Then call the path to that action in your image_tag. You obviously need to make sure the :type field has the right MIME type, add a route, etc.