tag:blogger.com,1999:blog-40318622092680511422024-03-07T21:06:39.444-08:00Ruby on Rails TutorialsEasy Ruby on Rails TutorialsSemper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-4031862209268051142.post-59557652601473148502013-10-16T04:27:00.000-07:002013-10-17T05:40:11.158-07:00How to set up production mode in Rails 4 with Thin and Apache<span style="font-family: inherit;"><span style="font-size: small;">I just completed a few days of research on the problem: how can Apache serve static assets while Thin runs Rails 4 application on the given port. Apache should create far-future expires headers on assets also. So, to do this, you need some</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;"><b>Apache modules</b>:</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">a2enmod proxy_balancer</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">a2enmod proxy_http</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">a2enmod rewrite</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">a2enmod headers</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">a2enmod expires</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<br />
<h4>
<span style="font-family: inherit;"><span style="font-size: small;"><b>My Apache virtualhost config:</b></span></span></h4>
<span style="font-family: inherit;"><span style="font-size: small;"><virtualhost><br /> ServerName my_site.com<br /> ServerAlias *.my_site.com<br /> DocumentRoot /home/my_path/my_app/public<br /><br /> RewriteEngine On<br /><br /> <proxy balancer:="" thinservers=""><br /> BalancerMember http://127.0.0.1:5000<br /> </proxy><br /> <br /> <location assets=""><br /> Header unset ETag<br /> FileETag None<br /> ExpiresActive On<br /> ExpiresDefault "access plus 1 year"<br /> </location><br /><br /> RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f<br /> RewriteRule ^/(.*)$ balancer://thinservers%{REQUEST_URI} [P,QSA,L]<br /><br /> # Custom log file locations<br /> ErrorLog /home/my_path/my_app/log/error.log<br /> CustomLog /home/my_path/my_app/log/access.log combined<br /><br /></virtualhost></span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">After then, restart your Apache service:</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">service apache2 restart</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">That was Apache configuration thanks to this post: </span></span><br />
<span style="font-family: inherit;"><span style="color: black; font-size: small;"><a href="http://bibwild.wordpress.com/2012/11/20/apache-conf-for-rails-asset-pipeline" target="_blank">http://bibwild.wordpress.com/2012/11/20/apache-conf-for-rails-asset-pipeline</a></span></span><br />
<span style="font-family: inherit;"><span style="font-size: large;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: large;"><br /></span></span>
<br />
<h4>
<span style="font-family: inherit;"><span style="font-size: small;"><b>Setting up Thin</b></span></span></h4>
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">There is my thin configuration file in <b>/etc/thin</b> directory. Set environment to production <b>my_site_name.yml</b>:</span></span><br />
<span style="font-family: inherit;"><span style="font-size: x-small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">chdir: /home/my_path/my_app<br />environment: production<br />address: 0.0.0.0<br />port: 5000<br />timeout: 30<br />log: log/thin.log<br />pid: tmp/pids/thin.pid<br />max_conns: 1024<br />max_persistent_conns: 100<br />require: []<br />wait: 30<br />servers: 1<br />daemonize: true<br />onebyone: true<br />user: my_user_name<br />group: my_user_name<br />tag: my_site_name-publ</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">I made a script in application's <b>bin/</b> directory, <b>my_site_name</b>:</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">#!/bin/sh<br />#<br /><br /># Start the service <br />start() {<br /> thin start -C /etc/thin/my_site_name.yml <br />}<br /><br /># Stop the service <br />stop() {<br /> thin stop -C /etc/thin/my_site_name.yml <br />}<br /><br /># Start the service <br />restart() {<br /> thin restart -C /etc/thin/my_site_name.yml <br />}<br /><br />### main logic ###<br />case "$1" in<br /> start)<br /> start<br /> ;;<br /> stop)<br /> stop<br /> ;;<br /> restart)<br /> restart<br /> ;;<br /> *)<br /> echo "Usage: $0 {start|stop|restart}"<br /> exit 1<br />esac<br /><br />exit 0</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">This is important for start / stop / restart your Rails 4 application easily. Set this file executable. Then just restart Thin like this, in you app's directory:</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">bin/my_site_name restart</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<br />
<h4>
<span style="font-family: inherit;"><span style="font-size: small;"><b>Configuration for production mode</b></span></span></h4>
<span style="font-family: inherit;"><span style="font-size: small;">First install yui-compressor gem to minify CSS also.</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">After then, insert gem 'therubyracer' to production section into <b>gemfile</b>.<br /> </span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">source 'https://rubygems.org'<br /><br />gem 'rails', '4.0.0'<br />gem 'mysql2'<br />gem 'sass-rails', '~> 4.0.0'<br /><br />gem 'uglifier', '>= 1.3.0'<br />gem 'yui-compressor','~> 0.12.0'<br />gem 'coffee-rails', '~> 4.0.0'<br />gem 'coffee-script-source', '1.5.0'<br />gem 'therubyracer', platforms: :ruby<br /><br />gem 'jquery-rails'<br />gem 'turbolinks'<br />gem 'jquery-turbolinks'<br /><br />gem 'jbuilder', '~> 1.2'<br /><br />group :doc do<br /> # bundle exec rake doc:rails generates the API under doc/api.<br /> gem 'sdoc', require: false<br />end<br /><br />gem 'execjs'<br />gem 'savon'<br />gem 'faye'<br />gem 'thin'<br /><br />group :production do<br /> gem 'therubyracer'<br />end</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">And run 'sudo bundle install'</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">See <b>config/environments/production</b> file:</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">MySiteName::Application.configure do<br /><br /> # Code is not reloaded between requests.<br /> config.cache_classes = true<br /><br /> # Eager load code on boot. This eager loads most of Rails and<br /> # your application in memory, allowing both thread web servers<br /> # and those relying on copy on write to perform better.<br /> # Rake tasks automatically ignore this option for performance.<br /> config.eager_load = true<br /><br /> # Full error reports are disabled and caching is turned on.<br /> config.consider_all_requests_local = false<br /> config.action_controller.perform_caching = true<br /><br /> # Disable Rails's static asset server (Apache or nginx will already do this).<br /> <b> config.serve_static_assets = false</b><br /> <br /> # Compress JavaScripts and CSS.<br /> config.assets.js_compressor = :uglifier<br /><b> config.assets.css_compressor = :yui</b><br /><br /> # Do not fallback to assets pipeline if a precompiled asset is missed.<br /> <b> config.assets.compile = false</b><br /><br /> # Generate digests for assets URLs.<br /><b> config.assets.digest = true</b><br /><br /> # Version of your assets, change this if you want to expire all your assets.<br /> config.assets.version = '1.0'<br /><br /> # Specifies the header that your server uses for sending files.<br /> <b> config.action_dispatch.x_sendfile_header = nil </b>#"X-Sendfile" # for apache<br /><br /> # Set to :debug to see everything in the log.<br /> config.log_level = :info<br /><br /> # Precompile additional assets.<br /> # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.<br /><b> config.assets.precompile = ['*.js', '*.js.erb', '*.css', '*.css.erb', '*.js.coffee.erb']<br /> config.assets.precompile << %w(*.png *.jpg *.jpeg *.gif *.ico)<br /> config.assets.precompile += [ "images/icons/*" ]</b><br /><br /> # Ignore bad email addresses and do not raise email delivery errors.<br /> # Set this to true and configure the email server for immediate delivery to raise delivery errors.<br /> config.action_mailer.raise_delivery_errors = false<br /><br /> # Enable locale fallbacks for I18n (makes lookups for any locale fall back to<br /> # the I18n.default_locale when a translation can not be found).<br /> config.i18n.fallbacks = true<br /><br /> # Send deprecation notices to registered listeners.<br /> config.active_support.deprecation = :notify<br /><br /> # Disable automatic flushing of the log to improve performance.<br /> config.autoflush_log = false<br /><br /> # Use default logging formatter so that PID and timestamp are not suppressed.<br /> config.log_formatter = ::Logger::Formatter.new<br />end</span></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><span style="font-size: small;">Don't forget to set config.action_dispatch.x_sendfile_header to nil and pay attention to precompile section. Add image subfolders and image extensions also.</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br />
Now you have to compile assets to public/assets directory, but first empty cache and assets files:</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">rm -rf tmp/*</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">rm -rf public/assets/*</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;">RAILS_ENV=production bundle exec rake assets:precompile</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">Don't forget to restart your Rails 4 application, but probably needs to kill thin process because assets files has been changed.</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">See this post also, it helped me a lot:</span></span><br />
<span style="font-family: inherit;"><span style="color: black; font-size: small;"><a href="http://blog.55minutes.com/2012/02/untangling-the-rails-asset-pipeline-part-1-caches-and-compass/" target="_blank">http://blog.55minutes.com/2012/02/untangling-the-rails-asset-pipeline-part-1-caches-and-compass/</a></span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">And the result is a simple live <a href="http://maths.laboratorygame.com/" target="_blank">mathematical practice site</a>.</span></span><br />
<span style="font-family: inherit;"><span style="font-size: small;"><br /></span></span>
<span style="font-family: inherit;"><span style="font-size: small;">That's all, good luck!</span></span>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com2tag:blogger.com,1999:blog-4031862209268051142.post-66330202483616523062012-02-29T03:37:00.004-08:002012-02-29T04:06:53.830-08:00Rails 3 ajax Autocomplete with jQuery and jQuery UI themeSo we want a form element with autocomplete. First thing to do is installing jquery-rails and jquery-ui-themes gems and require in Gemfile.<br />
<br />
Then require one of the jQuery UI theme into app/assets/stylesheets/application.css<br />
<pre class="brush: html"> *= require_self
*= require_tree .
*= require_style
*= require jquery-ui/ui-lightness
*/
</pre><br />
app/assets/javascripts/application.js<br />
<br />
<pre class="brush: html">//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require_tree .
</pre><br />
Our controller responds json object in apps/controllers/accounts_controller.rb<br />
<pre class="brush: ruby"> def search_account
@accounts=Account.where("LOWER(name) LIKE ?", "%#{params[:name].downcase}%").limit(params[:maxRows]).order(:name)
respond_to do |format|
format.json {render :json => @accounts}
end
end
</pre><br />
<br />
I've created a helper for input element app/helpers/application_helper.rb<br />
(Take care of heredoc strings.)<br />
<br />
<pre class="brush: ruby"> def autocomplete_input(attributes={})
#*need* object: this form's object : "person"
#*need* instance: searcheable object : 'account'
# instance_key: primary key of this instance : 'account_id'
# value: original or default value for instance : 'Yahoo Corp.'
# value_key: original or default value for instance_key: 252
#*need* ajax_url: remote url for ajax call without format: url_for(:controller=> :accounts, :action=> :search, :id=>'all')
# ajax_query_additional_params (Array): ["maxRows: 7", "anything :20"]
#*need* ajax_query_searchable_param Object's string (String): "name" (@person.account.name)
#*need* ajax_query_searchable_param_key Object's foreign key (String): "id" (@person.account.id)
# min_length minimal chars to start searching: 2
if attributes.nil? then return false end
if attributes.empty? then return false end
object=attributes[:object]
instance=attributes[:instance]
if object.nil? or instance.nil? then return false end
object=object.to_s.downcase
instance=instance.to_s.downcase
instance_key=attributes[:instance_key] || instance + "_id"
value=attributes[:value] || ""
value_key=attributes[:value_key] || ""
value_key_html=""
unless value_key.to_s.empty? then
value_key_html=" value=\""+value_key.to_s+"\""
end
ajax_url=attributes[:ajax_url]
ajax_query_additional_params=attributes[:ajax_query_additional_params] || ""
ajax_query_searchable_param=attributes[:ajax_query_searchable_param] || "name"
ajax_query_searchable_param_key=attributes[:ajax_query_searchable_param_key] || "id"
min_length=attributes[:min_length] || 2
ajax_query_additional_params_formatted=""
unless ajax_query_additional_params.nil? then
case ajax_query_additional_params
when Array then
i=0
ajax_query_additional_params.each do |aqap|
if i==0 then
ajax_query_additional_params_formatted=ajax_query_additional_params_formatted + aqap.to_s
else
ajax_query_additional_params_formatted=ajax_query_additional_params_formatted + ",\n" + aqap.to_s
end
i=i.next
end
when String then
ajax_query_additional_params_formatted=ajax_query_additional_params
when Hash then
i=0
ajax_query_additional_params.each do |aqap_key,aqap_value|
if i==0 then
ajax_query_additional_params_formatted=ajax_query_additional_params_formatted + aqap_key.to_s + ": " + aqap_value.to_s
else
ajax_query_additional_params_formatted=ajax_query_additional_params_formatted + ",\n" + aqap_key.to_s + ": " + aqap_value.to_s
end
i=i.next
end
end
end
jquery_request_data_params="data: {\n"
unless ajax_query_additional_params_formatted.empty? then
jquery_request_data_params=jquery_request_data_params + ajax_query_additional_params_formatted + ",\n"
end
jquery_request_data_params=jquery_request_data_params + "#{ajax_query_searchable_param}: request.term\n},"
search_field_id="search_#{object}_#{instance}"
value_div_id="#{object}_#{instance}_log"
hidden_field_id="#{object}_#{instance_key}"
hidden_field_name="#{object}[#{instance_key}]"
function_log_name="log_#{object}_#{instance}"
html_text = <<HTML1
<table><tbody><tr>
<td><input id="#{search_field_id}" class="ui-autocomplete-input"/></td>
<td><div id="#{value_div_id}" class="ui-widget-content">#{value}</div></td>
</tr></tbody></table>
<input type="hidden" id="#{hidden_field_id}" name="#{hidden_field_name}" #{value_key_html} >
HTML1
js_text = <<JS1
$(function() {
function #{function_log_name}( label, id ) {
$( "##{value_div_id}" ).html(label);
$( "##{hidden_field_id}").val(id);
}
$( "##{search_field_id}" ).autocomplete({
source: function( request, response ) {
$.ajax({
url: "#{ajax_url}.json",
dataType: "json",
#{jquery_request_data_params}
success: function( data ) {
response( $.map( data, function( item ) {
return {
label: item.#{ajax_query_searchable_param},
value: item.#{ajax_query_searchable_param},
id: item.#{ajax_query_searchable_param_key}
}
}));
}
});
},
minLength: #{min_length},
select: function( event, ui ) {
if (ui.item) {
#{function_log_name}( ui.item.value, ui.item.id );
} else {
#{function_log_name}( this.value, this.value );
}
},
open: function() {
$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
},
close: function() {
$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
}
});
});
JS1
concat(raw(javascript_tag(js_text)))
concat(raw(html_text))
end
</pre><br />
Finally insert autocomplete element in _form.htm.erb<br />
<br />
<pre class="brush: html"><div class="ui-widget">
<label for="search_account">Account:</label><br />
<% autocomplete_input(:object => "person",
:instance => "account",
:instance_key => "account_id",
:value => (@person.account.name unless @person.account.nil?),
:value_key => @person.account_id,
:ajax_url => url_for(:controller => 'accounts',
:action => 'search_account',
:id => 'all'),
:ajax_query_additional_params => {:maxRows => 7},
:ajax_query_searchable_param => "name",
:ajax_query_searchable_param_key => "id",
:min_length => 2
)%>
</div>
</div>
</pre><br />
Works with Rails 3.2 and jQuery JavaScript Library v1.7.1. Good luck! Questions?Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com2tag:blogger.com,1999:blog-4031862209268051142.post-68495488448136204242011-08-09T07:47:00.000-07:002011-08-14T21:37:13.583-07:00How to create scriptaculous ajax inplace editor fields in Rails3 with validationFirst, we should do our html view in app/views/ips/index.html:<br />
<br />
<pre class="brush: html"><div id="ips_table_div">
<%= render "ips_table" %>
</div>
</pre><br />
Then, we create the table and the javascript code in our partial view (app/views/ips/_ips_table.html.erb).<br />
<br />
<pre class="brush: html"><table cellpadding="10"><tbody>
<% unless @ips.nil? %>
<tr>
<td id="ip_new_ip_td_div">
<%= form_tag url_for(:controller => :ips,
:action => :create_ip),
:remote => true,
:id => "new_ip" %>
<%= text_field_tag "ip" %>
<%= submit_tag t(:add_button, :scope => [:application]), :id => "new_ip_submit" %>
</form>
</td>
<td>
</td>
</tr>
<% @ips.each do |ip| %>
<tr>
<td id="ip_ip_td_div_<%=ip.id %>">
<div id="ip_ip_text_div_<%=ip.id %>"><%= ip.ip %></div>
</td>
<td>
<%= link_to t(:delete_link, :scope => [:application]),
url_for(:controller => :ips,
:action => :delete_ip,
:id => ip.id),
:remote => true,
:confirm => t(:ip_delete_confirm, :scope => [:application])%>
</td>
</tr>
<% end %>
<% end %>
</tbody></table>
<script type="text/javascript">
var ip_validate_background_color_error = "#fff999";
var ip_validate_border_color_error = "#f80000";
var ip_validate_background_color = "#ffffff";
var ip_validate_border_color = "#999999";
var ipModifyFormOptions= $H({
cancelText:'<%=t :cancel_link, :scope => [:application] %>',
okText: 'ok',
savingText: '<%=t :saving_text, :scope => [:application] %>',
loadingText: '<%=t :loading_text, :scope => [:application] %>',
clickToEditText: '<%=t :click_to_edit_text, :scope => [:application] %>',
});
<% unless @ips.nil? %>
Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color;
Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color;
Form.findFirstElement('new_ip').setAttribute("onkeypress","return input_filter_exact(event, 'ip')");
$('new_ip_submit').disabled=true;
new Form.Observer('new_ip', 0.3, function(form, value) {
if(validateIpAddress(Form.findFirstElement('new_ip').value, false) == true) {
Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color;
Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color;
$('new_ip_submit').disabled=false;
} else {
Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color_error;
Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color_error;
$('new_ip_submit').disabled=true;
}
});
<% @ips.each do |ip| %>
new Ajax.InPlaceEditor('ip_ip_text_div_<%=ip.id %>', '<%= url_for :controller => :ips, :action => :modify_ip, :id => ip.id %>', ipModifyFormOptions.merge({
formId: 'ip_ip_form_<%=ip.id %>',
onEnterEditMode: function(form, value) {
setTimeout(function() {
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color;
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color;
Form.findFirstElement('ip_ip_form_<%=ip.id %>').setAttribute("onkeypress","return input_filter_exact(event, 'ip')");
new Form.Observer('ip_ip_form_<%=ip.id %>', 0.3, function(form, value) {
if(validateIpAddress(Form.findFirstElement('ip_ip_form_<%=ip.id %>').value, false) == true) {
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color;
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color;
$('ip_ip_form_<%=ip.id %>').elements[1].disabled=false;
} else {
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color_error;
Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color_error;
$('ip_ip_form_<%=ip.id %>').elements[1].disabled=true;
}
});
}, 1000);
}
}).toObject());
<% end %>
<% end %>
</script></pre><br />
Then we should make the controller (app/controllers/ips_controller.rb):<br />
<br />
<pre class="brush: ruby">respond_to :js, :only => [:delete_ip, :create_ip]
respond_to :html, :except => [:delete_ip, :create_ip]
layout :application, :except => [:delete_ip, :create:ip, :modify_ip]
layout false, :only => [:delete_ip, :create:ip, :modify_ip]
def index
@ips=Ip.all
respond_with(@ips)
end
def delete_ip
Ip.destroy(params[:id])
# it will returns a javascript code by default, so have to do the
# app/views/ips/delete_ip.js.erb, what will loads the table completely
@ips=Ip.all
respond_with(@ips)
end
def create_ip
ip=Ip.new(params[:ip]).save
# it will returns a javascript code, so have to do the
# app/views/ips/create_ip.js.erb, what will loads the table completely
@ips=Ip.all
respond_with(@ips)
end
def modify_ip
ip=Ip.find(params[:id])
ip.update_attribute(:ip, params[:value])
# don't forget some validations here also
# it will returns a html code, so have to do the
# app/views/ips/modify_ip.html.erb, what will contains the new text only, or:
respond_to do |format|
format.html { render :text => ip.ip }
end
end</pre><br />
Then we can create returned javascript codes app/views/ips/create_ip.js.erb and delete_ip.js.erb:<br />
<br />
<pre class="brush: js"> $("ips_table_div").innerHTML='';
$("ips_table_div").update("<%=escape_javascript(render(:template => "/ips/_ips_table.html.erb", :locals => {:ips => @ips})) %>");
</pre><br />
Finally we must define javascipt validation functions in public/apllication.js:<br />
<br />
<pre class="brush: js">function validateIpAddress(value, can_be_empty) {
if (arguments.length == 1) {
can_be_empty = false;
}
if (can_be_empty == true) {
if (value == null) {
return false;
}
if (value == "") {
return true;
}
}
if (value.match(/\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/))
{
if (value.length>0 && value.length<256)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
function input_filter_exact(e, type) {
var enabled_chars;
switch (type)
{
case "ip": enabled_chars="0123456789.";
break;
default: enabled_chars="-/.,_?[]()!abcdefghijklmnopqrstvuwxyzABCDEFGHIJKLMNOPQRSTVUWXYZ0123456789éáőúűóüöíÉÁŐÚÓÜÖÍ ";
}
var key;
var keychar;
if (window.event)
key = window.event.keyCode;
else if (e)
key = e.which;
else
return true;
keychar = String.fromCharCode(key);
if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) )
return true;
else if (((enabled_chars).indexOf(keychar) > -1))
return true;
else
return false;
} </pre><br />
<br />
That's all. Works with Rails 3.0.9, Prototype 1.7 and script.aculo.us v1.8.3Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com2tag:blogger.com,1999:blog-4031862209268051142.post-89844407477968496792011-08-03T06:58:00.000-07:002011-08-03T08:30:33.028-07:00How to sort mysql table by ip address string columnThere are lots of result for ordering mysql table by IP address string column on the net. These are almost hellish tricky. So I use this:<br />
<br />
<pre class="brush: ruby">ips=Ip.where(:reserved => false).order("INET_ATON(address) ASC")
</pre><br />
You can save numeric value of ip address also with<code class="literal"> INET_ATON</code>, then you can get the string value by "<code class="literal">INET_NTOA()</code>" mysql function.<br />
<br />
Here is the link about mysql miscellaneous functions:<br />
<a href="http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html"> http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html</a><br />
<br />
Good luck!Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0tag:blogger.com,1999:blog-4031862209268051142.post-47438261358288782492011-05-18T03:31:00.000-07:002011-05-18T03:46:57.922-07:00Scriptaculous Slider in Rails3 formSo there is an excellent slider. <a href="http://madrobby.github.com/scriptaculous/slider/">http://madrobby.github.com/scriptaculous/slider/</a> It is perfect to set up a select form element where values are predefined numbers or integers. First you have to download <a href="http://script.aculo.us/downloads">http://script.aculo.us/downloads</a> the slider.js file and move it to the /public/javascripts directory. Then insert this row in your layout, /app/views/layouts/application.html.erb after the defaults.<br />
<br />
<%= javascript_include_tag "slider.js" %><br />
<br />
Then we define CSS style for the slider as the same as at the script.aculo.us homepage. (/app/public/stylesheets/style.css)<br />
<br />
<pre class="brush: css">div.slider {
width:256px;
margin:10px 0;
background-color:#ccc;
height:10px;
position: relative;
}
div.slider div.handle {
width:10px;
height:15px;
background-color:#f00;
cursor:move;
position: absolute;
}
</pre><br />
Then we create a helper for it. (/app/helpers/application_helper.rb)<br />
<br />
<pre class="brush: ruby">def slider(attributes={})
unless attributes.nil? then
values=attributes[:values]
default_value=attributes[:default_value].to_s
object=attributes[:object].to_s
instance=attributes[:instance].to_s
unit=attributes[:unit] || ""
text_div_id=object + "_" + instance + "_slider_text_div"
slider_id=object + "_" + instance + "_slider"
concat(raw(
"<div id=\"#{slider_id}\" class=\"slider\">
<div class=\"handle\"></div>
</div>"
))
concat(raw(hidden_field(object, instance, :value => default_value.to_i)))
concat(raw("<div id=\"#{text_div_id}\">" + default_value + " " + unit + "</div>"))
js_text = <<JS3
(function() {
var zoom_slider = $('#{slider_id}');
var text_div = $('#{text_div_id}');
var hidden_item = $('#{object + "_" + instance}');
var values=#{values.inspect};
var values_length = values.length;
var min=40;
var max=200;
var unit = Math.ceil((max - min) / values_length);
var range = $R(min, max - unit);
var pix_values = new Array();
for(i=1;i<=values_length;i++){
pix_values[i-1]=min + (unit * (i - 1));
}
var default_value=pix_values[#{values.index(default_value.to_i)}];
new Control.Slider(zoom_slider.down('.handle'), zoom_slider, {
range: range,
sliderValue: default_value,
increment: unit,
values: pix_values,
onSlide: function(value) {
text_div.innerHTML=values[pix_values.indexOf(value)] + " #{unit}";
hidden_item.value=values[pix_values.indexOf(value)];
},
onChange: function(value) {
text_div.innerHTML=values[pix_values.indexOf(value)] + " #{unit}";
hidden_item.value=values[pix_values.indexOf(value)];
}
});
})();
JS3
concat(raw(javascript_tag(js_text)))
end
end</pre><br />
Then just define your form element in your view / form:<br />
<br />
<pre class="brush: ruby"><table><tbody><tr><td>
<% slider :object => "config",
:instance => "mem_size",
:unit => "MB",
:values => [512, 1024, 1536, 2048, 2560, 3072, 4096].sort,
:default_value => 1024 %>
</td></tr></tbody></table>
</pre><br />
That"s all! Questions?Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com30tag:blogger.com,1999:blog-4031862209268051142.post-15441429007289297792011-05-09T06:32:00.000-07:002011-05-09T06:38:23.169-07:00Rails3 UTF-8 support for strings<div style="font-family: inherit;">There is a general problem in rails 3 with utf8 string support. For example upcase, downcase, titleize or capitalize. Basically these methods produce ASCII strings because of lots of memory usage of unicode strings. mb_chars string method do the trick. Create a new rb file in /lib:<br />
</div><pre class="brush: ruby">[String].each do |klass|
klass.class_eval <<-RUBY, __FILE__, __LINE__
def utf8_downcase
mb_chars.downcase.to_s
end
def utf8_upcase
mb_chars.upcase.to_s
end
def utf8_capitalize
mb_chars.capitalize.to_s
end
def utf8_titleize
mb_chars.titleize.to_s
end
RUBY
end
</pre>
<div style="font-family: inherit;">Works with Rails 3.0.7 and Ruby 1.8 surely. Don't forget to put in config/application.rb this row after require 'rails/all':<br /><br />
Dir.glob("./lib/*.{rb}").each { |file| require file }
</div><div style="font-family: inherit;">Now you can call: <br /><br />
irb(main):005:0> "é ÉÚŐÚ ééé ŐŐÚSDFSF".utf8_downcase<br />
=> "é éúőú ééé őőúsdfsf"
<br />
<br />
That's all. Questions?
</div>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0tag:blogger.com,1999:blog-4031862209268051142.post-76469156619406678462011-03-03T06:25:00.000-08:002011-04-13T05:54:48.949-07:00How to submit an ajax form in javascript with Rails3 and Prototype<div style="font-family: inherit;">So there is a Rails 3 problem, when you want to submit a form in javascript (without a submit button), it is working on normal way, not ajax. But we can do creating a hidden submit button and then initializing a click event on it what is exactly doing ajax submission. The submit(); is not working anymore because it doesn't call the rails.js functions. It just works when you simple want to create a not ajax post without any confirmation. Let's see an ajax example in view's index.html.erb file:</div><br />
<pre class="brush: ruby"><%= form_tag "some_url",
:remote => true,
:method => :post,
:name => "some_procedure",
:id => "some_procedure" %>
<%= submit_tag 'procedure_submit_button', :id =>"procedure_submit_button" , :style => "display: none" %>
You can add here your html code for form and create some element what is doing the submission inside a table, for a td:
<td onclick="javascript: procedure_init();" style="cursor: pointer;">
put here an image for example
</td>
</form>
<%= javascript_tag <<-RUBY
function procedure_init()
{
var submit_button="procedure_submit_button";
var form_name="some_procedure";
// here you can build the form, or modify form parameters
$(submit_button).click();
}
RUBY
%>
</pre><br />
<div style="font-family: inherit;">If you have problems with sessions or current_user quits within ajax rendering, put this code to public/javascripts/application.js. /thanks to <a href="http://stackoverflow.com/questions/5124097/devise-rails-3-0-4-ends-session-after-ajax-request/">this answer</a>/</div><br />
<pre class="brush: js">document.observe("dom:loaded", function() {
Ajax.Responders.register({
onCreate: function(request) {
var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
if (csrf_meta_tag) {
var header = 'X-CSRF-Token',
token = csrf_meta_tag.readAttribute('content');
if (!request.options.requestHeaders) {
request.options.requestHeaders = {};
}
request.options.requestHeaders[header] = token;
}
}
});
});
</pre><br />
That's all. Questions?Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0tag:blogger.com,1999:blog-4031862209268051142.post-67504903866744255252010-11-22T01:23:00.000-08:002010-12-08T03:16:14.027-08:00Each loop for a class or model instance variablesSometimes we need to check all of instance variables in a class or model one by one. In this exaple we will check if a varaible is an Array or not:<br />
<br />
<pre class="brush: ruby">your_model.instance_variables.each do |i|
if your_model.instance_variable_get(i).instance_of?(Array) then
#your code to do anything with your_model.instance_variable_get(i) what is a value
end
end
</pre><br />
<br />
If you have an active record model, you can do:<br />
<br />
<pre class="brush: ruby">@account = Account.first
Account.column_names.each do |i|
@account.instance_eval(i)
# row returns @account.name for example inside the loop, next @account.address and so on
end
</pre><br />
<br />
<br />
<br />
That's all!Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com6tag:blogger.com,1999:blog-4031862209268051142.post-49045282036056571192010-11-22T00:37:00.000-08:002010-11-22T00:47:15.711-08:00How to get requested controller name, action name and id in Rails3 view<p>To get requested controller name, action name and id in view we will call a simple helper function. For example we have the '/users/show/23' request, by routing rule: 'match ':controller(/:action(/:id(.:format)))''</p><br />
<pre class="brush:ruby">#to get controller name:
<%= controller.controller_name %>
#=> 'users'
#to get action name, it is the method:
<%= controller.action_name %>
#=> 'show'
#to get id information:
<%= ActionController::Routing::Routes.recognize_path(request.url)[:id] %>
#=> '23'
</pre><br />
That's all!Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0tag:blogger.com,1999:blog-4031862209268051142.post-50252722330440573212010-11-08T05:40:00.000-08:002010-11-25T23:49:17.184-08:00I18n yml files in Rails3<p>Your locale files are located in config/locales directory by default. Let's make two locale files: en.yml and for example: hu.yml. In that files we can describe our string translations what we will use in our page view with helpers. Take care of yml rules, you can use spaces only instead of tabs, and spaces determine level of string. You can use double quotes to define a string, but if you want to use quotes inside the string, use html entity: " for it. You can use html in strings fo course, but don't forget raw helper in view before. Finally, you can give variables to yml simply, between %{var} (in rails2: {{var}} ) signs and full string needs to be between double quotes. I used to create yml blocks by controllers.</p><br />
<p>Labels are very simple also. Just take under helpers: and controller_name: (helpers: and contact: in the example below). Submit definitions are the same like labels.</p><br />
<pre class="brush: html">en:
contact:
prices:
show_price: "%{price_dollar}$"
quote: "Coordinator: & quot;Crucifixion?& quot? & lt;br /& gt; Mr. Cheeky: & quot;Er, no, freedom actually.& quot;"
attributes:
created_at: "Created at"
updated_at: "Updated at"
helpers:
submit:
contact:
create: "Order"
update: "Modify"
label:
contact:
name: "Your name"
company_name: "Company name"
phone: "Phone number"
email: "E-mail"
comment: "Comment"
date:
formats:
default: "%Y-%m-%d"
short: "%b %d"
long: "%B %d, %Y"
day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
order: [ :year, :month, :day ]
time:
formats:
default: "%a, %d %b %Y %H:%M:%S %z"
short: "%d %b %H:%M"
long: "%B %d, %Y %H:%M"
am: "am"
pm: "pm"
</pre><br />
<p>And the reference in our view file (apps/views/contact/index.html.erb):</p><br />
<pre class="brush: html"><%= form_for @contact, :as => :contact,
:url => {:action => 'new'},
:html => {} do |f| %>
<%=f.label :name %>
<%= f.submit %>
<%=t :show_price, :scope => [:contact, :prices], :price_dollar => 50 %>
<%=raw t(:quote, :scope => [:contact, :prices], :locale=>'en') %>
<%=l Date.today, :format => :long %>
</pre><br />
<p>You can define exact locale in view like :locale=>'hu'. Localize dates with l helper function. You can use I18n.locale in controller for getting current locale. You can get all locales in an array with: I18n.available_locales . Don't forget to check application.rb in config directory, where you can setting up default locale:</p><br />
<pre class="brush: ruby">config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.default_locale = :hu
</pre><br />
<p>Then make a method in app/controllers/application_controller.rb for users to change their language and create a before_filter:</p><br />
<pre class="brush: ruby">class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
def set_locale
locale = params[:locale] || session[:locale] || I18n.default_locale.to_s
locale = I18n.available_locales.include?(locale.to_sym) ? locale : 18n.default_locale.to_s
session[:locale] = I18n.locale = locale
end
end
</pre>
<p>Then create your link to set locale in your layout:
link_to('English', url_for(:locale => 'en')).
That's all! Questions?</p>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com1tag:blogger.com,1999:blog-4031862209268051142.post-71183374915839080412010-11-03T04:28:00.000-07:002011-04-13T05:57:23.140-07:00Rails3 ajax tricks with javascript erb templates<p>This guide is about rails3 ajax and javascript tricks. (Unobtrusive javascript, if it sounds better.) first, you must decide what do you want to do and how. Sometimes there are better solutions than we should think first. To call an ajax method, you must take the code in view header (or layout): <%= javascript_include_tag :defaults %></p><h4>Using js.erb templates.</h4><p>If you decided to use some ajax calls, using server-side programming, recommend to create a new ajax controller (but it's not necessary). In command line:</p><p><i>rails g controller ajax</i></p><p>Then, if we make an ajax call, we will define procession in app/controllers/ajax_controller.rb. Next, we define the javascript output in ajax_controller.rb with respond_to, and define our methods (now: empty_cart):</p><pre class="brush: ruby">class AjaxController < ApplicationController
respond_to :js
def empty_cart
Cart.where(:session_id => request.session_options[:id]).destroy_all
end
end
</pre><p>Then we can create empty_cart.js.erb in app/views/ajax/ directory. In this file we define javascript what sends to page. This is javascrip template, but we can use ruby expressions in it. Of course, we can use prototype methods and script.aculo.us effects. The partial cart.html has been defined in layouts and if cart is empty, it will show one row: "the cart is empty". The element will be replaced by partial:</p><br />
<pre class="brush: js">$("cart_div").update("<%= escape_javascript(render("layouts/partials/cart.html.erb")) %>");
new Effect.Highlight("cart_div", {duration: 1.5, startcolor: "#909090"});
</pre><br />
<p>After then, we can create this ajax link in our view, now: layouts/partials/cart.html.erb. We make it with a button defined in css.</p><pre class="brush: ruby"><% if Cart.where(:session_id => request.session_options[:id]).empty? %>
Cart is empty.
<% else %>
..put here your cart html code..
<%=raw form_tag url_for(:action => "empty_cart",
:controller => :ajax ),
{ :method => :post,
:remote => true,
'data-confirm' => "Are you sure?" } %>
<%=raw submit_tag "Empty Cart",
:id => "empty_cart_submit",
:class => "empty_cart_button"
%>
</form>
<% end %>
</pre><br />
<p>Don't forget to set link html options :remote => true, to call an ajax method.</p><p>The right syntax of the link_to function with i18n is:</p><br />
<pre class="brush:ruby"><%= link_to [t :empty_cart, :scope => [:application]],
url_for(:controller => 'ajax',
:action => "empty_cart"),
{:method => :post,
:remote => true,
:confirm => "Are you sure?"}
%>
</pre><br />
<br />
<h4>Using effects</h4><p>You can use any effects in javascript erb template like in pure javascript. For example a toggle effect:</p><br />
<pre class="brush: js">new Effect.toggle("some_div_<%= id %>", "slide", {duration: 0.2});
</pre><br />
<p>Don't forget to put ruby expressions between <%= %> tags like in html view.</p><br />
<h4>Forgetting observe_form and observe_field</h4><p>In rails 2 there were these functions observe_form and observe_field, now, in rails3 are missing. You can use <a href="https://github.com/rails/prototype_legacy_helper">Prototype Legacy Helper plugin</a>, or, I recommend to create your own javascript code, what is faster than calling an ajax method. Put your javascript code into your form view (app/views/controller_name/form.html.erb):</p><br />
<pre class="brush :ruby"><%=raw javascript_tag "
document.observe("dom:loaded", function()
{
new Form.Observer("<%= @jsvalidator.form.id %>", 0.3, function(form, value)
{
// now we got form values in one single url-formed linein value javascript variable
// so we create an array of key and value pairs in textArray
var textArray=unescape(value).split("&");
var i=0;
for(i=0; i<(textArray.length); i++)
{
// then, you can see all elements within a for loop
// now textArray[i] is one line like: "form_element_name=form_element_value"
value_line_with_equal_sign=textArray[i];
value_name="";
value_value="";
value_name=value_line_with_equal_sign.split("=",2)[0];
value_value=value_line_with_equal_sign.split("=",2)[1];
// now you can check all of form values in this loop, value_name is the form element name
// value_value is form element's value
// probably you must give form elements to Form class
}
}
}" %>
</pre><p>@jsvalidator object has been created in form's controller with form datas. See more information: <a href="http://ruby-on-rails-tutorials.blogspot.com/2010/10/how-to-generate-inline-javascript-by.html">How to generate inline javascript</a></p><p>If you have problems with Internet Explorer, IE see and download newer versions of rails.js and prototype.js. <a href="https://github.com/rails/prototype-ujs" >Details here.</a></p><br />
<div style="font-family: inherit;">If you have problems with sessions or current_user quits within ajax rendering, put this code to public/javascripts/application.js. /thanks to <a href="http://stackoverflow.com/questions/5124097/devise-rails-3-0-4-ends-session-after-ajax-request/">this answer</a>/</div><br />
<pre class="brush: js">document.observe("dom:loaded", function() {
Ajax.Responders.register({
onCreate: function(request) {
var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
if (csrf_meta_tag) {
var header = 'X-CSRF-Token',
token = csrf_meta_tag.readAttribute('content');
if (!request.options.requestHeaders) {
request.options.requestHeaders = {};
}
request.options.requestHeaders[header] = token;
}
}
});
});
</pre><br />
<br />
<p>That's all!</p>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com5tag:blogger.com,1999:blog-4031862209268051142.post-49055886402583272752010-10-26T06:48:00.000-07:002010-11-30T23:47:52.474-08:00How to load i18N locale files in rails3 with our new gem<p>That is very simple. We'll create a gem with our own locale files, first, we create the locale files in our gem's lib/locales directory (en.yml and hu.yml for example). There would be our gem's .rb file in lib directory (example.rb). Don't forget to specify these files in gemspec. Now we can create a new method: translate_string in our 'lib/example.rb'.</p><br />
<pre class="brush: ruby">class Example
require 'rubygems'
require 'active_support'
require 'i18n'
path=File.dirname(__FILE__)
I18n.load_path += Dir[ File.join(path, 'locales', '*.{rb,yml}') ]
def initialize
end
def translate_string(var)
return I18n.t(var, :scope=>[:example, :vars])
end
end
</pre><br />
<p>Then, we can create our locale files 'lib/locales/en.yml' like this:</p><br />
<pre class="brush: ruby">en:
example:
vars:
title: example
</pre><br />
<p>And our lib/locales/hu.yml:</p><br />
<pre class="brush: ruby">hu:
example:
vars:
title: példa
</pre><br />
<p>Take care of spaces instead of tabs. After we build our gem and insert to Gemfile (what is in our Rails3 application) we can call our new class in our controller. Don't forget to restart your application before.</p><br />
<code><br />
e=Example.new<br />
e.translate_string("title")<br />
</code><br />
<br />
<p>This gives "example". That's all!</p>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0tag:blogger.com,1999:blog-4031862209268051142.post-47488503534091334662010-10-25T02:27:00.000-07:002011-02-25T05:14:45.386-08:00Create new class in Rails3 with hash parameters<p>This guide is about how to create new class with hash parameters, without ActiveRecord. If you don't want to use database to define a new object, this guide is for you. First, we create a new contact.rb file in "app/models" directory</p><br />
<pre class="brush: ruby">class Contact
include ActiveModel::Serialization
attr_accessor :name, :company_name, :email, :phone, :comment
def initialize(attributes = {})
@name=attributes[:name]
@company_name=attributes[:company_name]
@email=attributes[:email]
@phone=attributes[:phone]
@comment=attributes[:comment]
end
# persisted is important not to get "undefined method `to_key' for" error
def persisted?
false
end
end
</pre><br />
<p>And then you can use this model to create a new form, like ActiveRecord in controllers:</p><p><i>@contact=Contact.new</i></p><p>or</p><p><i>@contact=Contact.new(params[:contact])</i></p><p>Now we can use this object to send email to sales or save it to another object's text column with json. For example if there is a json_contact text column in User active_record object, users.rb:</p><br />
<pre class="brush: ruby">Class User < ActiveRecord::Base
before_save :before_save_function
def before_save_function
unless self.json_contact.is_a?(String) then
# we need this condition because if we updating, must know if it is a String (json modelled class) or a Contact model class
self.json_contact=self.json_contact.to_json
end
true
end
def contact
unless self.json_contact.nil? then
contact_hash = ActiveSupport::JSON.decode(self.json_contact).symbolize_keys.clone
return Contact.new(contact_hash)
else
return nil
end
end
end
</pre>
<p>Then you can give a Contact object to User.json_contact like:</p><code>
@user=... # your turn (find, or create)
@contact=Contact.new(params[:contact])
@user.json_contact=@contact
@user.save</code>
<p>Don't forget to restart your application after modifying anything in your models. Now you can get original User.contact as an object, and you can use it like Contact model:</p><code>
contact_name=@user.contact.name
</code>
<p>That's all</p>Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com1tag:blogger.com,1999:blog-4031862209268051142.post-38931924155072377012010-10-20T07:14:00.000-07:002010-11-22T10:27:28.309-08:00How to generate inline javascript by gem for form validation etc...This tutorial is about generating an inline javascript by gem created by us. This can be usable for form validation or another javascript application. This tutorial is for Ruby on Rails 3. I don't write full code, because it could be too deep, I just try to show to you how to give inline javascript code by js template to a single view page.<br />
<br />
First, we need to create our own gem file structure:<br />
<br />
<blockquote>- jsvalidator<br />
<blockquote>- lib<br />
<blockquote>- jsvalidator.js.erb<br />
- jsvalidator.rb</blockquote>- jsvalidator.gemspec</blockquote></blockquote><br />
<br />
Then we edit the jsvalidator.gemspec file which is in jsvalidator directory have been created.<br />
<br />
<pre class="brush: ruby">Gem::Specification.new do |spec|
spec.name = 'jsvalidator'
spec.version ='0.0.1'
spec.files = ["lib/jsvalidator.js.erb", "lib/jsvalidator.rb"]
spec.summary = "Javascript form validator for rails3 with javascript."
spec.author = 'Programmer'
spec.email = 'programmer@yourdomain.com'
spec.homepage = 'http://www.yourdomain.com'
spec.has_rdoc = false
end </pre><br />
We create our class structure in jsvalidator.rb file. You can install erubis gem with "gem install erubis" command.<br />
<br />
<pre class="brush: ruby">require 'rubygems'
require 'active_support'
require 'erubis'
class Jsvalidator
# define a form object
attr_accessor :form
def form
return @form
end
# now we don't initialize anything, but you can set initial values in this block
def initialize
end
# we create a function to define our form, what is now an another object class defined later
def define_form(attributes={})
f=Form.new(attributes)
@form=f if f
end
# jsvalidator_helper is a function, we will call using Jsvalidator class
def jsvalidator_helper
# __FILE__ is the path where the this rb file is
path=File.dirname(__FILE__)
template_path=File.join(path, 'jsvalidator.js.erb')
# we can give objects to javascript template like @jsvalidator, what is self in this case,
# beacuse now we work with Jsvalidator class only
vars={ '@jsvalidator' => self }
# so read the javascript template
template= File.read(template_path)
# Erubis can execute inline ruby expressions with objects (formed like: <%= @jsvalidator.any %>)
javascript=Erubis::Eruby.new(template).result(vars)
# then we create return string
javascript="<script type="\"text/javascript\"">
//<![CDATA[
" + javascript + "
//]]>
</script>"
return javascript
end
#end of Jsvalidator class
end
# then we must define our Form class
class Form < Jsvalidator
# You can create any object in it, now we use form.id only
attr_accessor :id
def initialize(attributes={})
@id=attributes[:id]
end
end
</pre>In this file we should create our model, or data structure, we will use at jsvalidator.html.erb in another function of course. Then, we edit the jsvalidator.js.erb file. In this file we define our javascript code, but remember, this is a template, so you can use ruby expressions like: <%= @jsvalidator.anything %>, but first you must define objects in Form class. Now we use @form.id only.<br />
<pre class="brush: js">document.observe("dom:loaded", function()
{
new Form.Observer("<%= @jsvalidator.form.id %>", 0.3, function(form, value)
{
// now we got form values in one single url-formed linein value javascript variable
// so we create an array of key and value pairs in textArray
var textArray=unescape(value).split("&");
var i=0;
for(i=0; i<(textArray.length); i++)
{
// then, you can see all elements within a for loop
// now textArray[i] is one line like: "form_element_name=form_element_value"
value_line_with_equal_sign=textArray[i];
value_name="";
value_value="";
value_name=value_line_with_equal_sign.split("=",2)[0];
value_value=value_line_with_equal_sign.split("=",2)[1];
// now you can check all of form values in this loop, value_name is the form element name
// value_value is form element's value
// probably you must give form elements to Form class
}
}
} </pre><br />
After then, you can build your gem file at jsvalidator directory at command line:<br />
<br />
<i>gem build jsvalidator.gemspec</i><br />
<br />
and install:<br />
<br />
<i>sudo gem install jsvalidator</i><br />
<br />
Then edit your Gemfile, what is located at your rails3 application's directory, and insert this line with your real path:<br />
<pre class="brush: ruby">gem 'jsvalidator', :path = "/home/user/gems/jsvalidator", :require = "jsvalidator"
</pre>Then type command line:<br />
<br />
<i>bundler update</i><br />
<br />
If you don't want to create a working gem because of developing, you can just simply add to your application_controller.rb file this line with your path:<br />
<pre class="brush: ruby">require '/home/user/gems/jsvalidator/lib/jsvalidator.rb'
</pre><br />
Now at your view file, you just simply call helper like this:<br />
<pre class="brush: ruby"><% @jsvalidator=Jsvalidator.new %>
<% @jsvalidator.define_form( :id => "your_form_id" ) %>
<%= raw @jsvalidator.jsvalidator_helper %>
</pre>That's all.Semper Augustushttp://www.blogger.com/profile/00574515269390883328noreply@blogger.com0