Halaman

Rabu, 22 Desember 2010

[shared] change rails form error field wrapper

by default rails wrap all fields that contain error data using div with "fieldWithErrors" class

but sometimes we want to change that wrapper for example to use span instead of div.
that can easily be done by overriding field_error_proc class attribute in ActionView::Base

in environment.rb
ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}".html_safe }

file position (for rails 2.3.10):
[ruby_dir]\lib\ruby\gems\1.8\gems\actionpack-2.3.10\lib\action_view\helpers\active_record_helper.rb

[shared] rails render_invalid method

purpose


provide DRY solution for rendering (or redirecting) from controller on invalid request, such as failed validation on create/update

requirements


- jquery js framework
- notifications helper from my earlier post about custom ajax helper:
http://tech.maysora.com/2010/11/rails-custom-ajax-helper-for-jquery.html

codes


application_controller.rb
# render invalid request to show error message depend on request type
# example:
#   render_invalid "Update failed."
#     ajax: show error notification with message "Update failed."
#     html: simply render text "Update failed."
#   render_invalid "Save failed.", :render => {:action => "new"}
#     ajax: show error notification with message "Save failed."
#     html: render action new with "Save failed." flash message
#   render_invalid "Save failed.", :render => {:action => "new"}, :flash => false
#     same as above but without flash for html
#   render_invalid "You can't do that.", :redirect_to => {:action => "index"}, :flash => false, :status => :unauthorized
#     same as above but redirecting to index instead of rendering new for html
#     and using unauthorized(401) status instead of not_acceptable(406)
#   render_invalid "Update failed.", :object => @user, :fields_wrapping => true
#     ajax: show error notification with addition of object's error messages and wrap error fields with div class fieldWithErrors
#     html: same as ajax minus fields wrapping
def render_invalid message="Error.", options={:flash => true}
  options[:status] ||= :not_acceptable
  message += "
#{options[:object].errors.full_messages.join(' ')}
" if options[:object].present? respond_to do |format| format.js do render(:update, :status => options[:status]) do |page| page << notification_error(message) if options[:object].present? && options[:fields_wrapping] page.rjs_clean_error_fields request page.rjs_apply_error_fields options[:object], request end end end format.html do if options[:render].present? flash.now[:error] = message if options[:flash] render options[:render].try(:merge, {:status => options[:status]}) || {:text => message, :status => options[:status]} elsif options[:redirect_to].present? flash[:error] = message if options[:flash] redirect_to options[:redirect_to] else render :text => message, :status => options[:status] end end end end

application_helper.rb (only if you use ajax error fields wrapping)
def rjs_apply_error_fields object, request
  klass_name = object.class.name.underscore
  wrapper = "
" object.errors.each do |attr, msg| attr = attr.split(".") page << "var $fields = $(), $container = $('\##{klass_name}_#{object.id || "new"}');" page << "if(!$container.length) $container = $('form[action=\\'#{request.request_uri}\\']');" page << "if(!$container.length) $container = $(document);" if attr.length > 1 object.send(attr.first).each_with_index do |x,i| page << "$fields = $fields.add('[id^=#{klass_name}_#{attr.first}_attributes][id$=#{attr.last}]:eq(#{i}),label[for^=#{klass_name}_#{attr.first}_attributes][for$=#{attr.last}]:eq(#{i})', $container)" if x.errors.on(attr.last) end else page << "$fields = $('label[for=#{klass_name}_#{attr}],\##{klass_name}_#{attr}', $container);" end page << "if(!$fields.parent('.fieldWithErrors').length)" page << "$fields.wrap('#{wrapper}')" end end def rjs_clean_error_fields request page << "$('.fieldWithErrors.rjs_#{request.request_method}_#{request.request_uri.gsub(/_=\d+($|&)/, "").parameterize} *').unwrap();" end

usage

users_controller.rb (using non ajax form)
#...

def create
  @user = User.new(params[:user])
  unless @user.save
    render_invalid "Failed to register.", :object => @user, :render => {:action => "new"}
  else
    flash[:info] = "Registration success, please check your email to activate."
    redirect_to login_path
  end
end

#...
users_controller.rb (using ajax form)
#...

def update
  @user = current_user
  unless @user.update_attributes(params[:user])
    render_invalid "Profile update failed.", :object => @user, :fields_wrapping => true
  end
end

#...
and update.js.rjs (for success behavior)
page << notification_info "Profile updated."
page.rjs_clean_error_fields request # used for cleaning error fields wrapping
#... other necessary action ...

additional tips

depending on your site style, it might be a good idea to change the div wrapper in rjs_apply_error_fields helper to span. you can also change rails standard error field wrapper for non-ajax form, see this post

[shared] floating point error in js

console.log(0.1+0.2); //-> 0.30000000000000004
console.log(0.1*0.2); //-> 0.020000000000000004

solution:
1. use x.toFixed(n) if you only need 5 or less decimal digit
2. use function from http://www.codingforums.com/showpost.php?p=483962&postcount=9
3. best solution, use js BigDecimal library https://github.com/jhs/bigdecimal.js or http://stz-ida.de/index.php?option=com_content&view=article&id=18&Itemid=32

summary:
use number 1 if decimal precision isn't really important (most likely), or use number 3 with some performance cost

Minggu, 05 Desember 2010

foobar2k headphone surround setup

this guide will add 5.1 speaker simulation using headphone for foobar2k
the result isn't really perfect but it's noticeably increase surround effect and reduce sound inside head feels..

needed files:
- foobar2k http://www.foobar2000.org/download
- foo_input_dts http://www.foobar2000.org/components/view/foo_input_dts
- foo_channel_mixer http://skipyrich.com/wiki/Foobar2000:Channel_Mixer
- nvidia purevideo decoder http://www.nvidia.com/object/dvd_decoder_1.02-223-trial.html

step:
- install nvidia purevideo decoder, use the trial CC and activation code in the site
- install foobar
- copy foo_input_dts and foo_channel_mixer dll to [foobar installation folder]/components/
- run foobar, go to file, preferences, playback, DSP manager
- (optional) add resampler (PPHS) to active DSP, then configure it to 48000Hz Ultra mode
- add channel mixer
- configure channel mixer, general: output channels 6, check L C R RL RR, uncheck LFE, Stereo image width 1.00
- upmix: mode surround, mode surround, center 1.00, volume 2.00, all others 0.00
- add Dolby headphone, configure: dolbyhph.dll to C:\windows\system32\DolbyHph.dll
- (optional) add others DSP to the top of the list if you want, make sure channel mixer then dolby headphone is the last two on the list

other useful components:
- Skip silence
- foo_ui_columns (nice ui)
- foo_uie_lyrics (add lyric, need foo_ui_columns)
- foo_shutdown (auto shutdown/standby/hibernate)
- amip for foobar and amip configurator (add winamp like jump and now playing announce to messengers and irc)

original source: http://www.head-fi.org/forum/thread/447089/5-1-headphone-experience-foobar-configuration-for-all-stereo-music-files