Overriding ActionView::Base.field_error_proc in Rails - ruby

Right now I have my ActionView::Base.field_error_proc as
Proc.new do |html_tag, instance|
if html_tag =~ /^<label/ or instance.respond_to?(:object_name)
%{<div class="field_with_errors">#{html_tag}</div>}.html_safe
else
%{<div class="field_with_errors">#{html_tag}<br /><label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
end
I had modified this to accomodate a few of my needs when i did use the client_side_validations gems.
Right now, the 'fields_with_error' div wraps around the html_tag(i.e the error field to be specific). What i would like to know though is if its possible to modify the position of the div class="fields_with_error" and place it right after the div that contains the error_field.
For eg,
<div class="main_div">
<%= password_field_tag 'secret', 'Your secret here' %>
</div>
Then the div class="fields_with_error" should be postioned as
<div class="main_div">
<%= password_field_tag 'secret', 'Your secret here' %>
</div>
<div class="fields_with_error"> <label class="message"> The error message </label> </div>
Any help would be of great value.

So when I work with twitter bootstrap I usually make an initializer with something like this
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html = %(<div class="field_with_errors">#{html_tag}</div>).html_safe
# add nokogiri gem to Gemfile
form_fields = [
'textarea',
'input',
'select'
]
elements = Nokogiri::HTML::DocumentFragment.parse(html_tag).css "label, " + form_fields.join(', ')
elements.each do |e|
if e.node_name.eql? 'label'
html = %(<div class="control-group error">#{e}</div>).html_safe
elsif form_fields.include? e.node_name
if instance.error_message.kind_of?(Array)
html = %(<div class="control-group error">#{html_tag}<span class="help-inline"> #{instance.error_message.uniq.join(', ')}</span></div>).html_safe
else
html = %(<div class="control-group error">#{html_tag}<span class="help-inline"> #{instance.error_message}</span></div>).html_safe
end
end
end
html
end
This just adjust regular errors to twitter errors in forms :> so makes everything very nice to look at ;>. You can use same approach.
Cheers if this helps

Related

Images inserted into HTML properly but not displayed - size is 0*0px

I am using a HAML template of a bootstrap carousel to display all images from a folder.
The images should not be displayed with a size of 0 by 0 pixels. There is no CSS property that would be setting this, the width of the element is set to 100% in CSS and even changing the size in a browser console does nothing.
All the images are accessible directly from a browser otherwise (like http://localhost:4567/car-images/fb_1.jpg) and there are no 404 errors.
This is the HAML template with a block of Ruby code:
.col-sm-6#carousel
.carousel.slide#myCarousel{ "data-ride" => "carousel", :style => "height:inherit"}
%ol.carousel-indicators
.carousel-inner{ :role => "listbox"}
- #images.each do |image|
.item
%img{ :src => "car-images/#{image}"}
%a.left.carousel-control{ "data-slide" => "prev", :href => "#myCarousel", :role => "button"}
%span.glyphicon.glyphicon-chevron-left{ "aria-hidden" => "true"}
%span.sr-only Previous
%a.right.carousel-control{ "data-slide" => "next", :href => "#myCarousel", :role => "button"}
%span.glyphicon.glyphicon-chevron-right{ "aria-hidden" => "true"}
%span.sr-only Next
And this is how it renders in a browser:
<div class='col-sm-6' id='carousel'>
<div class='carousel slide' data-ride='carousel' id='myCarousel' style='height:inherit'>
<ol class='carousel-indicators'></ol>
<div class='carousel-inner' role='listbox'>
<div class='item'>
<img src='car-images/fb_1.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_2.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_3.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_4.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_5.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_6.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_7.jpg'>
</div>
<div class='item'>
<img src='car-images/fb_8.jpg'>
</div>
</div>
<a class='left carousel-control' data-slide='prev' href='#myCarousel' role='button'>
<span aria-hidden='true' class='glyphicon glyphicon-chevron-left'></span>
<span class='sr-only'>Previous</span>
</a>
<a class='right carousel-control' data-slide='next' href='#myCarousel' role='button'>
<span aria-hidden='true' class='glyphicon glyphicon-chevron-right'></span>
<span class='sr-only'>Next</span>
</a>
</div>
</div>
Also, the Ruby code that runs the view:
require 'sinatra'
require 'haml'
$car_img_dir = 'public/car-images'
get '/' do
#images = Dir.foreach($car_img_dir).select { |x| File.file?("# {$car_img_dir}/#{x}") }
haml :index
end
get '/about' do
haml :about
end
get '/products' do
haml :products
end
I have been trying to solve this for about 2.5 hours now, and being a beginner, I am unaware of any solutions.
Your use of a global is bad practice. I'd recommend learning about variable scoping and using constants. Eventually you'll learn why and when to use a global but until them it'd be better to avoid them.
The code in question could be written more idiomatically like:
CAR_IMG_DIR = 'public/car-images'
get '/' do
#images = Dir.foreach(CAR_IMG_DIR).select { |x| File.file?(File.join(CAR_IMG_DIR, x)) }
haml :index
end
Rather than assume that the path separator character is / you should let Ruby determine what it is and supply it. Using File.join allows Ruby to do that. See the beginning of the documentation for the IO class and join.
You can't trust the HTML that the browser shows you. Browsers can, and will, modify HTML. You can use curl or wget, or various HTTP clients for Ruby, or even HAML itself, to view the emitted HTML without the browser getting in the way. I'd recommend getting used to doing that; You always need to know how the browser will render the page, but just don't trust its rendered HTML to be an accurate rendition of the real HTML.
Regarding the image size of 0x0: You can change your template to set the size, or you can add CSS to do it for all images of that class. I'd add the CSS, but you're going to have to do it one place or another. By default the browser should show the images in their native sizes so something is telling the browser to set it to 0x0 and you need to override it. Perhaps looking at the style attributes of the images will give you an idea where the problem is.

Nokogiri or "string" to create this HTML fragment?

I need to create an HTML fragment to embed in a page (a simple js gallery). This is the HTML:
<div id="gallery-1" class="royalSlider rsDefault">
<a class="rsImg" data-rsw="632" data-rsh="500" data-rsbigimg="../img/paintings/2.jpg" href="../img/paintings/700x500/2.jpg">
Vincent van Gogh - The Starry Night
<img width="96" height="72" class="rsTmb" src="../img/paintings/t/2.jpg">
</a>
</div>
I can create this using string interpolation, but someone suggest me to use Nokogiri. I do not know how I can nest the nodes.
#doc = Nokogiri::HTML::DocumentFragment.parse ""
Nokogiri::HTML::Builder.with(#doc) do |doc|
g.pictures.each do |picture|
doc.create_element "a", :class => "rsImg"
end
end
Is it better to use Nokogiri, or can I also proceed with the easy way (string)? How can I create the nested structure I need?
Update
Done with Nokogiri
#doc = Nokogiri::HTML::DocumentFragment.parse ""
Nokogiri::HTML::Builder.with(#doc) do |doc|
doc.div(:id => 'content-gallery', :class => 'royalSlider rsDefault') {
g.pictures.each do |picture|
doc.a(:src => picture.image_url(:gallery), :class => 'rsImg') {
doc.img(:src => picture.image_url(:widget), :class => 'rsTmb')
}
end
}
end
#doc.to_html

Sinatra to-do list tutorial problems

So, I'm new to Ruby/Sinatra, did a bunch of codecademy lessons and the like. I decided until I actually built something, I wouldn't really understand some core concepts.
I found a tutorial for building a to-do list app in Sinatra, and all was fine and good until I got to the edit and delete functionality. I can read and write to/from the database, but whenever I try to edit or delete, it skips straight to "Note not found".
I couldn't figure this out myself, so I asked a developer friend of mine. When I sent him the code, everything worked absolutely fine for him! We tried a couple of different possible fixes, but to no end. I even downloaded the code from the guy's github, just in case there was a random mistake somewhere in my own code, to no avail.
So, I come here asking for some help! Why won't this work!
Clarification: Here's some of the code, where I think the problem may lie. In edit.erb and delete.erb, no matter what it is going to the else statement and sending me to "note not found". It's reading properly from the database, as my homepage can add and show notes.
recall.rb
get '/:id' do
#note = Note.get params[:id]
#title = "Edit note ##{params[:id]}"
erb :edit
end
put '/:id' do
n = Note.get params[:id]
n.content = params[:content]
n.complete = params[:complete] ? 1 : 0
n.updated_at = Time.now
n.save
redirect '/'
end
get '/:id/delete' do
#note = Note.get params[:id]
#title = "Confirm deletion of note ##{params[:id]}"
erb :delete
end
delete '/:id' do
n = Note.get params[:id]
n.destroy!
redirect '/'
end
edit.erb
<% if #note %>
<form action="/<%= #note.id %>" method="post" id="edit">
<input type="hidden" name="_method" value="put">
<textarea name="content"><%= #note.content %></textarea>
<input type="checkbox" name="complete" <%= "checked" if #note.complete %>>
<input type="submit">
</form>
<p>Delete</p>
<% else %>
<p>Note not found.</p>
<% end %>
delete.erb
<% if #note %>
<p>Are you sure you want to delete the following note: <em>"<%= #note.content %>"</em>?</p>
<form action="/<%= #note.id %>" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Yes, Delete It!">
Cancel
</form>
<% else %>
<p>Note not found.</p>
<% end %>
Moving the delete-route above the other routes seemed to work for me, which would suggest that the /:id -part in the route definition catches the /delete-part as well. You can see the generated regexps with Sinatra::Application.routes.
Here's a minimal:
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'dm-sweatshop'
# Models
DataMapper.setup(:default, 'sqlite::memory:')
class Note
include DataMapper::Resource
property :id, Serial
property :content, Text, :required => true
property :complete, Boolean, :default => false
property :created_at, DateTime, :default => lambda {Time.now}
property :updated_at, DateTime
before(:save) { attribute_set(:updated_at, Time.now) }
end
DataMapper.finalize.auto_migrate!
# Fixtures
Note.fix {{
:content => /\w+/.gen
}}
100.of { Note.gen }
# Routes
before("/:id") {|id| #note = Note.get id }
get("/:id/delete") {|id| #note = Note.get id; erb :delete }
get("/:id") { erb :edit }
put "/:id" do
#note.attributes = params["note"]
#note.save ? redirect(to("/")) : erb(:edit)
end
delete("/:id") { #note.destroy; redirect(to("/")) }
# Templates
template :layout do
'<!DOCTYPE html>
<html>
<body><%= yield %></body>
</html>'
end
template :edit do
'<% if #note %>
<form action="/<%= #note.id %>" method="POST">
<input type="hidden" name="_method" value="PUT">
<textarea name="note[content]"><%= #note.content %></textarea>
<input type="checkbox" name="note[complete]"
<%= #note.complete? && "checked" %> >
<input type="submit">
</form>
<p>Delete</p>
<% else %>
<p>Note not found.</p>
<% end %>'
end
template :delete do
'<% if #note %>
<p>Are you sure you want to delete the following note:
<em>"<%= #note.content %>"</em>?</p>
<form action="/<%= #note.id %>" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Yes, Delete it!">
Cancel
</form>
<% else %>
<p>Note not found</p>
<% end %>'
end
I don't know if this is still interesting someone, but a simple
params[:id].to_i
fixed it for me.

Haml renders input element as escaped

I have a haml like ;
= form_for #company, :html => {:multipart => true}, :url => update_user_company_path do |f|
.field
Title:#{f.text_field :name}
= f.fields_for :attachments do |builder|
- if builder.object.new_record?
.field
= builder.hidden_field :name, :value => 'logo'
= builder.file_field :file
- elsif builder.object.name.eql?('logo') && !builder.object.file.url.eql?('/files/original/missing.png')
.field
%span.thumbnail
= link_to "Delete", delete_company_attachment_path(#company, builder.object), :method => :delete, :class => "remove_image"
= image_tag builder.object.file.url, :style => "height:86px;width:125px"
= f.submit 'Ok'
Chrome renders this code as intended, but in Firefox it is like;
<form method="post" id="edit_company_29" enctype="multipart/form-data" class="edit_company" action="/users/25/company" accept-charset="UTF-8"><div style="margin:0;padding:0;display:inline"><input type="hidden" value="✓" name="utf8"><input type="hidden" value="put" name="_method"><input type="hidden" value="thisismytokenvalue=" name="authenticity_token"></div>
<div class="field">
Title:<input type="text" value="sdgdfgghjh" size="30" name="company[name]" id="company_name">
</div>
<input id="company_attachments_attributes_0_id" name="company[attachments_attributes][0][id]" type="hidden" value="114" /><input id="company_attachments_attributes_1_id" name="company[attachments_attributes][1][id]" type="hidden" value="115" /><div class="field">
<input type="hidden" value="logo" name="company[attachments_attributes][2][name]" id="company_attachments_attributes_2_name">
<input type="file" name="company[attachments_attributes][2][file]" id="company_attachments_attributes_2_file">
</div>
<input type="submit" value="Ok" name="commit">
</form>
Why is an element escaped. If you check haml, you can see I didn't put them.
Where did it come from?
Why is it happening?
Wow ... I've just had a similar issue. My guess is that if you pass nil to the form_builder's fields_for the hidden_input isn't returned with html_safe. To quickly fix that add a
-else
=""
after the whole elsif block
You must return something other than nil in the fields_for block.
This issue has been fixed in Haml 4.0.4 by mattwildig, with the help of #lulalala. Here is an explanation of the problem:
The #fields_for helper generates a hidden input field for each record, which it adds to the result of capturing the block. Normally the return value of capture will be a SafeBuffer, so this won’t be escaped. However if the block doesn’t write anything to the buffer then Haml returns a literal empty String from capture. The hidden input element is concatted to this string, and when it is combined with the rest of the entries, since it is a String being added to a SafeBuffer, it gets escaped.

In Ruby, via Sinatra, how do I get a link within an `li` tag?

I am using erb and ideally, I would like my html to look like this:
<li class="selected">Look at this awesome page</li>
Where both the path for the link, and the class for the li are dynamically generated using an instance variable.
Thoughts?
Edit 1
If I were using something like Rails, I know I could probably do something like:
<%= link_to content_tag(:li, nil, awesome_path, :class => "selected") %>
But that would produce the opposite effect, where the <a> would be outside of the <li> and not inside where I want it.
That's called a helper:
helpers do
def li_with_a options
'<li class="' + options[:class] + '">' + options[:text] + '</li>'
end
end
and from erb:
<%= li_with_a :class => 'selected', :url => 'awesome.html', :text => 'Look at this text' %>
Should be as easy as:
<li class="<%= #li_class %>">
Look at this awesome page
</li>
Of course you have to change the instance variables accordingly.

Resources