Screencast: Syntax Highlighting

Syntax Highlighting wird die visuelle Aufbereitung von Source-Code genant. Die meisten Texteditoren unterstützen Syntax Highlighting, aber auch Web wird gerne darauf zurückgegriffen um Quellcode lesbarer zu machen. Ryan zeigt diese Woche wie man in Ruby/Rails-Applikationen um Syntax Highlighting bereichern kann.

 

Download:

Download (30.9 MB, 9:09)
Alternativer Download für iPod & Apple TV (24.4 MB, 9:09)

 

Resourcen:

 

Quellcode:

[html]
<%= textilize(coderay(@article.content)) %>
[/html]

[ruby]
# config/environment.rb
config.gem "coderay"
config.gem "RedCloth"

# application_helper.rb
def coderay(text)
text.gsub(/<code( lang="(.+?)")?>(.+?)</code>/m) do
content_tag("notextile", CodeRay.scan($3, $2).div(:css => :class))
end
end

# syntax_benchmark.rb
require "rubygems"
require "benchmark"
require "coderay"
require "uv"

path = __FILE__
content = File.read(__FILE__)

# run it once to initialize
CodeRay.scan("print ‚hello’", "ruby").div(:css => :class)
Uv.parse("print ‚test’", "xhtml", "ruby", true, "amy")

Benchmark.bm(11) do |b|
b.report("coderay") do
50.times { CodeRay.scan(content, "ruby").div(:css => :class) }
end

b.report("ultraviolet") do
50.times { Uv.parse(content, "xhtml", "ruby", true, "amy") }
end

b.report("pygments") do
50.times { `pygmentize -f html "#{path}"` }
end
end
[/ruby]

[css]
.CodeRay {
background-color: #232323;
border: 1px solid black;
font-family: ‚Courier New‘, ‚Terminal‘, monospace;
color: #E6E0DB;
padding: 3px 5px;
overflow: auto;
font-size: 12px;
margin: 12px 0;
}
.CodeRay pre {
margin: 0px;
padding: 0px;
}

.CodeRay .an { color:#E7BE69 } /* html attribute */
.CodeRay .c { color:#BC9358; font-style: italic; } /* comment */
.CodeRay .ch { color:#509E4F } /* escaped character */
.CodeRay .cl { color:#FFF } /* class */
.CodeRay .co { color:#FFF } /* constant */
.CodeRay .fl { color:#A4C260 } /* float */
.CodeRay .fu { color:#FFC56D } /* function */
.CodeRay .gv { color:#D0CFFE } /* global variable */
.CodeRay .i { color:#A4C260 } /* integer */
.CodeRay .il { background:#151515 } /* inline code */
.CodeRay .iv { color:#D0CFFE } /* instance variable */
.CodeRay .pp { color:#E7BE69 } /* doctype */
.CodeRay .r { color:#CB7832 } /* keyword */
.CodeRay .rx { color:#A4C260 } /* regex */
.CodeRay .s { color:#A4C260 } /* string */
.CodeRay .sy { color:#6C9CBD } /* symbol */
.CodeRay .ta { color:#E7BE69 } /* html tag */
.CodeRay .pc { color:#6C9CBD } /* boolean */
[/css]

Screencast: Unobtrusive Javascript in Rails 3

Wie in den Vorgängerversionen unterstützt auch Rails 3 bei der Integration von JavaScript. Ryan zeigt diese Woche welche Möglichkeiten Rails 3 bietet.

 

Download:

Download (27.4 MB, 13:18)
Alternativer Download für iPod & Apple TV (17.7 MB, 13:18)

 

Resourcen:

 

Quellcode:

[html]
<!– ujs_example.html –>
<!DOCTYPE html>
<html>
<head>
<title>UJS Example</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
$(function() {
$("#alert").click(function() {
alert(this.getAttribute("data-message"));
return false;
})
})
</script>
</head>
<body>
<h1><a href="#" id="alert" data-message="Hello UJS!">Click Here</a></h1>
</body>
</html>

<!– layouts/application.html.erb –>
<%= javascript_include_tag :defaults %>
<!– or –>
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "jquery.rails.js" %>
<%= csrf_meta_tag %>

<!– products/index.html.erb –>
<% form_tag products_path, :method => :get, :remote => true do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>

<div id="products">
<%= render @products %>
</div>
[/html]

[html]
// products/index.js.erb
$("products").update("<%= escape_javascript(render(@products)) %>");
// or
$("#products").html("<%= escape_javascript(render(@products)) %>");
[/html]

Screencast: Schutz vor XSS in Rails 3

XSS (Cross-Site Scripting), eine Bezeichnung für das Ausnutzen von Sicherheitslücken innerhalb von Webanwendungen, sollte in allen WEB-Applikationen unterbunden werden. Ryan zeigt in dieser Woche welche Änderungen in Rails 3 den Entwickler dabei unterstützt, um von Anfang an mögliche Sicherheitslücken zu vermeiden.

 

Download:

Download (15.7 MB, 8:56)
alternative download for iPod & Apple TV (11.1 MB, 8:56)

 

Resourcen:

 

Quellcode:

[html]
<!– views/comments/_comment.html.erb –>
<div class="comment">
<%= strong link_to(comment.name, comment.url) %>
<p><%= comment.content %></p>
</div>
[/html]

[ruby]
# rails
"foo".html_safe?
safe = "safe".html_safe
safe.html_safe?

# application_helper.rb
def strong(content)
"<strong>#{h(content)}</strong>".html_safe
end
[/ruby]

Screencast: Rails für mobile Geräte

Der mobile Markt wächst stetig weiter und hat andere Anforderungen an Webapplikationen auf dem mobilen Gerät als für Desktop-Geräte. Ryan zeigt in seinem Screencast wie Rails angepasst werden kann um mobile Geräte zu unterstützen. Dabei kommt mitunter jQTouch zum Einsatz.

 

Download:

Download (55.4 MB, 13:26)
alternative download for iPod & Apple TV (22.4 MB, 13:26)

 

Resourcen:

Quellcode:

[ruby]
# config/initializers/mime_types.rb
Mime::Type.register_alias "text/html", :mobile

# application_controller.rb
before_filter :prepare_for_mobile

private

def mobile_device?
if session[:mobile_param]
session[:mobile_param] == "1"
else
request.user_agent =~ /Mobile|webOS/
end
end
helper_method :mobile_device?

def prepare_for_mobile
session[:mobile_param] = params[:mobile] if params[:mobile]
request.format = :mobile if mobile_device?
end
[/ruby]

[html]
<!– views/layouts/application.html.erb –>
<%= stylesheet_link_tag ‚mobile‘ if mobile_device? %>

<p>
<% if mobile_device? %>
<%= link_to "Full Site", :mobile => 0 %>
<% else %>
<%= link_to "Mobile Site", :mobile => 1 %>
<% end %>
</p>

<!– views/layouts/application.mobile.erb –>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title><%= h(yield(:title) || "Untitled") %></title>
<%= stylesheet_link_tag "/jqtouch/jqtouch.min.css", "/jqtouch/themes/apple/theme.min.css" %>
<%= javascript_include_tag "/jqtouch/jquery.1.3.2.min.js", "/jqtouch/jqtouch.min.js", "mobile" %>
<%= yield(:head) %>
</head>
<body>
<div class="current">
<%- if show_title? -%>
<div class="toolbar">
<%= link_to "Back", nil, :class => "back" unless current_page? root_path %>
<h1><%=h yield(:title) %></h1>
<%= link_to "Full Site", root_url(:mobile => 0), :class => "button", :rel => "external" %>
<%= yield(:toolbar) %>
</div>
<%- end -%>

<% unless flash.empty? %>
<div class="info">
<%- flash.each do |name, msg| -%>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<%- end -%>
</div>
<% end %>

<%= yield %>
</div>
</body>
</html>

<!– views/projects/index.mobile.erb –>
<% title "Projects" %>

<ul>
<% for project in @projects %>
<li class="arrow">
<%= link_to h(project.name), project %>
<small class="counter"><%= project.tasks.size %></small>
</li>
<% end %>
</ul>

<ul><li class="arrow"><%= link_to "New Project", new_project_path %></li></ul>
[/html]

Screencast: Mehrere Daten gleichzeitig bearbeiten

Mehrere Einträge in Formular gleichtzeitig zu bearbeiten erfordert gewisse Anpassungen bzw. Vorkehrngen. Eine Möglichkeit wie dies gelöst werden kann zeigt Ryan diese Woche in seinem Screencast.

Download

Download (33.6 MB, 13:53)
Alternativer Download für iPod & Apple TV (19.8 MB, 13:53)

Ressourcen:

Quellcode:

[ruby]
# products_controller.rb
def edit_individual
@products = Product.find(params[:product_ids])
end

def update_individual
@products = Product.update(params[:products].keys, params[:products].values).reject { |p| p.errors.empty? }
if @products.empty?
flash[:notice] = "Products updated"
redirect_to products_url
else
render :action => "edit_individual"
end
end

# routes.rb
map.resources :products, :collection => { :edit_individual => :post, :update_individual => :put }
[/ruby]

[html]
<!– views/products/index.html.erb –>
<% form_tag edit_individual_products_path do %>
<table>
<tr>
<th></th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
</tr>
<% for product in @products %>
<tr>
<td><%= check_box_tag "product_ids[]", product.id %></td>
<td><%=h product.name %></td>
<td><%=h product.category.name %></td>
<td><%= number_to_currency product.price %></td>
<td><%= link_to "Edit", edit_product_path(product) %></td>
<td><%= link_to "Destroy", product, :confirm => ‚Are you sure?‘, :method => :delete %></td>
</tr>
<% end %>
</table>
<p>
<%= select_tag :field, options_for_select([["All Fields", ""], ["Name", "name"], ["Price", "price"], ["Category", "category_id"], ["Discontinued", "discontinued"]]) %>
<%= submit_tag "Edit Checked" %>
</p>
<% end %>

<!– views/products/edit_individual.html.erb –>
<% form_tag update_individual_products_path, :method => :put do %>
<% for product in @products %>
<% fields_for "products[]", product do |f| %>
<h2><%=h product.name %></h2>
<%= render "fields", :f => f %>
<% end %>
<% end %>
<p><%= submit_tag "Submit" %></p>
<% end %>

<!– views/products/_fields.html.erb –>
<%= f.error_messages :object_name => "product" %>
<% if params[:field].blank? || params[:field] == "name" %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<% end %>
<% if params[:field].blank? || params[:field] == "price" %>
<p>
<%= f.label :price %><br />
<%= f.text_field :price %>
</p>
<% end %>
<% if params[:field].blank? || params[:field] == "category_id" %>
<p>
<%= f.label :category_id %><br />
<%= f.collection_select :category_id, Category.all, :id, :name %>
</p>
<% end %>
<% if params[:field].blank? || params[:field] == "discontinued" %>
<p>
<%= f.check_box :discontinued %>
<%= f.label :discontinued %>
</p>
<% end %>
[/html]

Screencast: Formulare mit verschachtelten Modellen Teil 2

In dieser Woche geht es weiter mit dem zweiten Teil von Ryans Screencast zu dem Thema „Formulare mit verschachtelten Modellen“. Er wie weitere Felder dynamisch mit JavaScript, über Prototype oder Query, hinzugefügt werden können.

Download:

Download (15.9 MB, 12:40)
alternative download for iPod & Apple TV (20.2 MB, 12:40)

 

Resourcen:

Quellcode:

[html]
<!– _form.html.erb –>
<p><%= link_to_add_fields "Add Question", f, :questions %></p>

<!– _question_fields.html.erb –>
<%= link_to_remove_fields "remove", f %>

<p><%= link_to_add_fields "Add Answer", f, :answers %></p>

<!– _answer_fields.html.erb –>
<%= link_to_remove_fields "remove", f %>
[/html]

[javascript]
// application.js
function remove_fields(link) {
$(link).previous("input[type=hidden]").value = "1";
$(link).up(".fields").hide();
}

function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).up().insert({
before: content.replace(regexp, new_id)
});
}

// application_jquery.js
function remove_fields(link) {
$(link).prev("input[type=hidden]").val("1");
$(link).closest(".fields").hide();
}

function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).parent().before(content.replace(regexp, new_id));
}
[/javascript]

Screencast: Formulare mit verschachtelten Modellen

Fomulare mit verschachtelten Modellen lassen sich viel einfacher mit der Methode accepts_nested_attributes erstellen. Wie diese Methode benutzt werden kann, zeigt Ryan in seinem dieswöchigen Screencast.

Download:

Download (22.4 MB, 11:09)
Alternativer Download für iPod & Apple TV (15.2 MB, 11:09)

 

Resourcen:

Quellcode:

[bash]
rails surveysays
script/generate nifty_layout
script/generate nifty_scaffold survey name:string
script/generate model question survey_id:integer content:text
script/generate model answer question_id:integer content:string
rake db:migrate
[/bash]

[ruby]
# models/survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end

# models/question.rb
class Question < ActiveRecord::Base
belongs_to :survey
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end

# models/answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
end

# surveys_controller.rb
def new
@survey = Survey.new
3.times do
question = @survey.questions.build
4.times { question.answers.build }
end
end
[/ruby]

[html]
<!– views/surveys/_form.html.erb –>
<% form_for @survey do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<% f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>

<!– views/surveys/_question_fields.html.erb –>
<p>
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows => 3 %><br />
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Question" %>
</p>
<% f.fields_for :answers do |builder| %>
<%= render ‚answer_fields‘, :f => builder %>
<% end %>

<!– views/surveys/_answer_fields.html.erb –>
<p>
<%= f.label :content, "Answer" %>
<%= f.text_field :content %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove" %>
</p>
[/html]

Screencast: Embedded Association

Diese Woche zeigt Ryan Bates in seinem Screencast wie selbstreferenzierende DB-Beziehungen (one-to-many, many-to-many) umgesetzt werden können.

Download (18.7 MB, 14:03)
Alternativer Download für iPod & Apple TV (15.4 MB, 14:03)

Ressourcen:

Quellcode:

One to many:

[bash]
script/generate migration add_role_to_users role:string
rake db:migrate
[/bash]

[ruby]
# models/user.rb
class User < ActiveRecord::Base
acts_as_authentic
has_many :articles
has_many :comments

ROLES = %w[admin moderator author]

def role_symbols
[role.to_sym]
end
end
[/ruby]

[ror]
<!– users/new.html.erb –>
<p>
<%= f.label :role %><br />
<%= f.collection_select :role, User::ROLES, :to_s, :titleize %>
</p>
[/ror]

Many to many

[bash]
script/generate migration add_roles_mask_to_users roles_mask:integer
rake db:migrate
[/bash]

[ruby]
# models/user.rb
class User < ActiveRecord::Base
acts_as_authentic
has_many :articles
has_many :comments

named_scope :with_role, lambda { |role| {:conditions => "roles_mask & #{2**ROLES.index(role.to_s)} > 0"} }

ROLES = %w[admin moderator author]

def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end

def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end

def role_symbols
roles.map(&:to_sym)
end
end
[/ruby]

[ror]
<!– users/new.html.erb –>
<p>
<%= f.label :roles %><br />
<% for role in User::ROLES %>
<%= check_box_tag "user[roles][]", role, @user.roles.include?(role) %>
<%=h role.humanize %><br />
<% end %>
<%= hidden_field_tag "user[roles][]", "" %>
</p>
[/ror]