How to Create GEMS
Very simple to create a GEM
1. Create the directory structure
.
--- Rakefile
--- bin
--- hello_anderson
--- hello_anderson.gemspec
--- lib
--- hello_anderson.rb
--- test
--- test_hello_anderson.rb
Inside lib it is necessary to have a rb file with the same name of the GEM.
Ex:
class HelloAnderson
def self.say_hello
puts "Hello Anderson!"
end
end
hello_anderson.gemspec is responsible for model the gem. Inside it we have what the gem is and its version.
Ex:
Gem::Specification.new do |s|
s.name = 'hello_anderson'
s.version = '0.0.0'
s.date = '2013-12-12'
s.summary = "Hellow Anderson!"
s.description = "Example of a gem saing hello to Anderson"
s.authors = ["Anderson Araujo Lopes"]
s.email = 'romalopes@yahoo.com.br'
s.files = ["lib/hello_anderson.rb", other files...]
s.homepage =
'http://rubygems.org/gems/hello_anderson'
s.license = 'MIT'
end
To build a GEM
$ gem build hello_anderson.gemspec
To install a GEM
$ gem install ./hello_anderson-0.0.0.gem
To use a GEM
use: require "hello_anderson"
HelloAnderson.say_hello
The published geuemms are in:
http://rubygems.org/
Process:
1. To setup the computer with your RubyGems account:
$ curl -u qrush https://rubygems.org/api/v1/api_key.yaml >
~/.gem/credentials; chmod 0600 ~/.gem/credentials
2 . gem push hello_anderson-0.0.0.gem
To see the GEM in rubygems.org
$ gem list -r hello_anderson
To install the GEM from rubygems.org
$ gem install hola
Adding a executable
place the file bin/hello_anderson
chmod a+x bin/hello_anderson
#!/usr/bin/env ruby
require 'hello_anderson'
puts Hola.say_hello()
To run the GEM
$ ruby -Ilib ./bin/hello_anderson
Test
Fill Rakefile
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs << 'test'
end
desc "Run tests"
task :default => :test
Fill test/test_hello_anderson.rb
require 'test/unit'
require 'hello_anderson'
class HelloAndersonTest < Test::Unit::TestCase
def test_hello_anderson
assert_equal "Hello Anderson", HelloAnderson.say_hello
end
end
run test
$ rake test
OR
$ rake
Document
Gems use RDoc to generate docs
romalopes
Blog about technology and programming.
quarta-feira, 15 de janeiro de 2014
Ruby on Rails-Action Mailer Basics
====
Based on guides.rubyonrails.org
Action Mailer Basics
Send eails using mailer classes and views
Class inherit from ActionMailer::Base and live in app/mailers
Mailers are conceptually similar to controllers
Steps
1. Create the mailer
$ rails generate mailer UserMailer
user_mailer.rb created
class UserMailer < ActionMailer::Base
default from: 'from@example.com' <-- br="" default="" from=""> end
2. It is possible jusst to create the Mailer in app/mailers
class MyMailer < ActionMailer::Base
end
3. Add a method called welcome
def welcome_email(user)
@user = user
@url = 'http://example.com/login'
mail(to: @user.email, subject: 'Welcome to My Awesome Site')
end
4. Create the views/user_mailer/welcome.html.erb
Welcome to example.com, <%= @user.name %>
You have successfully signed up to example.com,
your username is: <%= @user.login %>.
To login to the site, just follow this link: <%= @url %>.
Thanks for joining and have a great day!
4.1 It is possible to create a text(non html) file too. welcome_email.text.erb
With method webcome_email, rails will automatically render both html and text files.
5. In method create of UsersController
if @user.save
# Tell the UserMailer to send a welcome Email after save
UserMailer.welcome_email(@user).deliver
-->
Ruby on Rails-Working with JavaScript in Rails
====
Based on guides.rubyonrails.org
Working with JavaScript in Rails
Unobtrusive JavaScript
Jaav uses a "Unobtrusive javaScript" technique
EX:
< a href="#" data-background-color="#990000">Paint it red< /a>
data-background is called in unobtrusive way because there is no mix between JavaScript and HTML
Call:
paintIt = (element, backgroundColor, textColor) ->
element.style.backgroundColor = backgroundColor
if textColor?
element.style.color = textColor
$ ->
$("a[data-background-color]").click ->
backgroundColor = $(this).data("background-color")
textColor = $(this).data("text-color")
paintIt(this, backgroundColor, textColor)
Built-in Helpers
Many view helper methods to assist generating HTML.
form_for
<%= form_for(@post, remote: true) do |f| %>
...
<% end %>
form_tag
<%= form_tag('/posts', remote: true) %>
link_to
<%= link_to "a post", @post, remote: true %>
<%= link_to "Delete post", @post, remote: true, method: :delete %>
in CoffeScript, uses
$ -> $("a[data-remote]").on "ajax:success", (e, data, status, xhr) -> alert "The post was deleted."
or in directly
<%= link_to "delete", account, method: :delete, data: { confirm: "You sure?" } %>
button_to
<%= button_to "A post", @post, remote: true %>
The server side
Usually, AJAX requests return JSON rather than HTML
Controller
class UsersController < ApplicationController
def index
@users = User.all
@user = User.new
end
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.js {}
format.json { render json: @user, status: :created, location: @user }
else
format.html { render action: "new" }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
index.html.erb
< b >Users< /b >
< ul id="users"> <----- appendto="" br="" fill="" here="" in="" js="" the="" will=""> <% @users.each do |user| %>
<%= render user %> <----- _user.html.erb="" br="" render="" the=""> <% end %>
< /ul >
< br>
<%= form_for(@user, remote: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
_user.html.erb
< li ><%= user.name %>< /li >
create.js.erb
It is called by the method create.
$("<%= escape_javascript(render @user) %>").appendTo("#users");
Turbolinks
Uses AJAX to speed up page rendering in most applications
It attaches a click handler to all < a > tags
What to do
Include turbolinks in Gemfile
in app/assets/javascripts/application.js
//= require turbolinks
To disable turbolink
< a href="..." data-no-turbolink>No turbolinks here< /a>.
----->----->
terça-feira, 14 de janeiro de 2014
Ruby on Rails-Rails Routing from the Outside In
====
Based on guides.rubyonrails.org
Rails Routing from the Outside In
The Purpose of the Rails Router
Simple example:
GET /patients/17
Route
get '/patients/:id', to: 'patients#show'
Or
get '/patients/:id', to: 'patients#show', as: 'patient'
and your application contains this code in the controller:
@patient = Patient.find(17)
and this in the corresponding view:
<%= link_to 'Patient Record', patient_path(@patient) %>
Route will generate
/patients/17
CRUD, Verbs, and Actions
If declare
resources :photos
If creates 7 routes
HTTP Verb Path
GET /photos index
GET /photos/new new
POST /photos create
GET /photos/:id show
GET /photos/:id/edit edit
PATCH/PUT /photos/:id update
DELETE /photos/:id destroy
Singular resources
To call
/profile
route
get 'profile', to: 'users#show'
A singular resourceful route generates these helpers:
new_photo_path returns / photo /new
edit_ photo _path returns / photo /edit
photo _path returns / photo
Controller Namespaces and routing
It is possible to organize groups of controllers under a namespace
EX:
namespace : admin do
resources :posts, :comments
end
It will create routes for post and comments . For Admin::PostController
GET /admin/posts admin_post_path
GET /admin/posts/new new_admin_post_path
POST /admin/posts/:id admin_post_path(:id)
etc
Uses Admin::PostController without the prefix /admin, just declares:
scope module: ‘admin’ do
resources :posts, :comments
end
OR
resources :posts, module:’admin’
To use /admin/post without admin in path.
Scope ‘/admin’ do
Resources :posts, :comments
End
Resources :posts, path: ‘/admin/posts’
GET /admin/posts posts_path
GET /admin/posts/new new_post_path
Nested Resources
when there are resources that are children of others.
Models:
class Magazine < ActiveRecord::Base
has_many
:ads
end
end
class Ad < ActiveRecord::Base
belongs_to :magazine
end
Resources:
resources :magazines do
resources :ads
end
/magazines/:magazine_id/ads
/magazines/:magazine_id/ads/new
/magazines/:magazine_id/ads
The url: edit_magazine_ad_path
It is possible to nest 2 levels
resources :publishers do
resources :magazines do
resources :photos
end
end
Calling:
/publishers/1/magazines/2/photos/3
Paths and URLs From Objects
resources :magazines do
resources :ads
end
You can pass instances of magazines and ads
<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>
Or
<%= link_to 'Ad details', url_for([@magazine, @ad]) %>
Or
<%= link_to 'Ad details', [@magazine, @ad] %>
Rails will se magazines and ads and create the path.
To call Edit
<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>
Adding More RESTful Actions
Add Member Routes
resources :photos do
member do
get 'preview'
end
end
Provides:
GET /photos/1/preview
and preview_photo_url and preview_photo_path helpers
segunda-feira, 2 de dezembro de 2013
Ruby on Rails-Action Controoler Overview
====
Based on guides.rubyonrails.org
Controller
is the C from MVC
Controller
Name
Preferable in plural:
ClientsController
Methods and
Actions
Normal ruby class the inherits
from ApplicationController
Ex /clients/new:
class
ClientsController < ApplicationController
def new
@client
= Client.new
end
end
Parameters
Rails doesn't make any
distinction between GET or POST parameters
# In the example:
def create
@client = Client.new(params[:client])
if @client.save
redirect_to @client
else
# This line overrides the default
rendering behavior, which
# would have been to render the
"create" view.
render "new"
end
end
# Values came from
<form accept-charset="UTF-8" action="/clients" method="post">
<input type="text" name="client[name]" value="Acme" />
<input type="text" name="client[phone]" value="12345" />
<input type="text" name="client[address][postcode]" value="12345" />
<input type="text" name="client[address][city]" value="Carrot City" />
</form>
JSON parameters
If working with
JSON, Rails convert automatically the parameters in parms hash.
Routing
parameters
Hash params always contains
:controller and :action keys
Strong
parameters
Action Controller parameters can
be used in Active Model mass assigments only after they pass through another
method(whitelisted). The params will be
chosen to be exposed.
Ex:
class
PeopleController < ActionController::Base
def
update
person =
current_account.people.find(params[:id])
person.update_attributes!(person_params)
redirect_to
person
end
private
def person_params
params.require(:person).permit(:name,
:age)
end
end
Session
Kinds of session:
ActionDispatch::Session::CookieStore
- Stores everything on the client.
ActionDispatch::Session::CacheStore
- Stores the data in the Rails cache.
ActionDispatch::Session::ActiveRecordStore
- Stores the data in a database using Active Record. (require
activerecord-session_store gem).
ActionDispatch::Session::MemCacheStore
- Stores the data in a memcached cluster
If you need a different session
storage mechanism, you can change it in the
config/initializers/session_store.rb file.
ex:
RomaMoneyRails::Application.config.session_store
:cookie_store, key: '_romaMoneyRails_session', domain: ".example.com"
#domain is
optional
CookieStore used for signing the
session data
Can be changed
in config/initializers/secret_token.rb:
EX, create a
random value:
require
'securerandom'
def
secure_token
token_file = Rails.root.join('.secret')
if File.exist?(token_file)
# Use the existing token.
File.read(token_file).chomp
else
# Generate a new token and store it in
token_file.
token = SecureRandom.hex(64)
File.write(token_file, token)
token
end
end
RomaMoneyRails::Application.config.secret_key_base
= secure_token
Accessing Session
def
current_user
@_current_user ||=
session[:current_user_id] &&
User.find_by(id:
session[:current_user_id])
end
def
create
if user =
User.authenticate(params[:username], params[:password])
# Save the user ID in the session so it
can be used in
# subsequent requests
session[:current_user_id] = user.id
redirect_to root_url
end
end
To
reset the intire session:
reset_session
Flash
Special
part of session that is cleared in each request. It will available only in the
next request.
Ex:
flash[:notice]
= "You have successfully logged out."
Cookie
To
store cookie is similar to Session
#
Remember the commenter's name.
cookies[:commenter_name] = @comment.author
Render xml and JSON data
class
UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render xml: @users} # automatically invokes
@users.to_xml
format.json { render json: @users}
end
end
end
Render JSON with JavaScript
@user = User.first
respond_to do |format|
format.html {
redirect_to root_url }
format.js
end
Should have a
file js.erb with the same name of the action
Filter
Runs
before, after or "arround" the controller action
There
are different ways to access Filters, but these are the most known ones
before_action
Ex:
class
ApplicationController < ActionController::Base
before_action :require_login
private
def require_login
unless logged_in?
flash[:error] = "You must be logged
in to access this section"
redirect_to new_login_url # halts request
cycle
end
end
end
-
this will be run on every controller
Ex
of before_action for user_controller.rb
before_action
:signed_in_user,
only:
[:index, :edit, :update, :destroy, :change_to_this, :change_account,
:change_account_ajax]
before_action
:correct_user, only: [:edit, :update]
before_action
:admin_user, only: :destroy
Skiping
before for some methods
class
LoginsController < ApplicationController
skip_before_action :require_login, only:
[:new, :create]
end
after_action
After
is similar to before.
Has
access to response.
Can't
stop the action
arround_action
Run
the associated actions by yielding
Request Forgery Protection
First
step to protect destructive actions from forgery it prohibit GET requests(REST
already does this)
Request and Response objects
Request
Object
query_parameters
- sent as part of the query string
request_parameters
- sent as part of the post body
path_parameters
- parameters that were recognized by the routing as being part of the path
leading to this particular controller and action.
Response
Object
response.headers["Content-Type"]
= "application/pdf"
HTTP Authentications
Basic
Authentication
Very
simple
class
AdminsController < ApplicationController
http_basic_authenticate_with name:
"humbaba", password: "5baa61e4"
end
Digest
Authentication
only
requires using one method, authenticate_or_request_with_http_digest
Streaming and File Downloads
send_data
To
stream data to the client, use send_data:
Ex:
#Generate
a stream and send it
require
"prawn"
class
ClientsController < ApplicationController
# Generates a PDF document with information
on the client and
# returns it. The user will get the PDF as a
file download.
def download_pdf
client = Client.find(params[:id])
send_data generate_pdf(client),
filename:
"#{client.name}.pdf",
type: "application/pdf"
end
private
def generate_pdf(client)
Prawn::Document.new do
text client.name, align: :center
text "Address:
#{client.address}"
text "Email: #{client.email}"
end.render
end
end
send_file
To
send a file
class
ClientsController < ApplicationController
# Stream a file that has already been generated
and stored on disk.
def download_pdf
client = Client.find(params[:id])
send_file("#{Rails.root}/files/clients/#{client.id}.pdf",
filename:
"#{client.name}.pdf",
type:
"application/pdf") #default=application/octet-stream
end
end
It
read 4kb at time avoid loading the entire file to memory at once. It can be configure.
RESTFUL
download
First
include in config/initializers/mime_types.rb:
Mime::Type.register
"application/pdf", :pdf
class
ClientsController < ApplicationController
# The user can request to receive this
resource as HTML or PDF.
def show
@client = Client.find(params[:id])
respond_to do |format|
format.html
format.pdf { render pdf:
generate_pdf(@client) }
end
end
end
Log Filtering
Uses a
log file
Rescue
Useful
to send a specific exception to a page
ex:
class
ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound,
with: :record_not_found
private
def record_not_found
render text: "404 Not Found",
status: 404
end
end
Force ssl
In
config/environments/production.rb
#
Force all access to the app over SSL, use Strict-Transport-Security, and use
secure cookies.
config.force_ssl = true
Of for a specific action and
controller
class
DinnerController
force_ssl only: :cheeseburger
# or
force_ssl except: :cheeseburger
end
Ruby on Rails-Action View Form Helpers
====
Based on guides.rubyonrails.org
Most Simple
use xxx_tag
<%=
form_tag("/search", method: "get") do %>
<%= label_tag(:q, "Search for:")
%>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
Passing controller and action
form_tag(controller:
"people", action: "search", method: "get", class:
"nifty_form")
#
=> '
#OR
form_tag({controller:
"people", action: "search"}, method: "get",
class: "nifty_form")
#
=> '
Different helpers
Checkboxs
<%=
check_box_tag(:pet_cat) %>
<%=
label_tag(:pet_cat, "I own a cat") %>
Result:
<input id="pet_cat" name="pet_cat" type="checkbox" value="1" />
<label for="pet_cat">I own a cat</label>
RadioBox
<%=
radio_button_tag(:age, "child") %>
<%=
label_tag(:age_child, "I am younger than 21") %>
Result:
<input id="age_child" name="age" type="radio" value="child" />
<label for="age_child">I am younger than 21</label>
Others
<%=
text_area_tag(:message, "Hi, nice site", size: "24x6")
%>
<%=
password_field_tag(:password) %>
<%=
hidden_field_tag(:parent_id, "5") %>
<%=
search_field(:user, :name) %>
<%=
telephone_field(:user, :phone) %>
<%=
date_field(:user, :born_on) %>
<%=
datetime_field(:user, :meeting_time) %>
<%=
datetime_local_field(:user, :graduation_day) %>
<%=
month_field(:user, :birthday_month) %>
<%=
week_field(:user, :birthday_week) %>
<%=
url_field(:user, :homepage) %>
<%=
email_field(:user, :address) %>
<%=
color_field(:user, :favorite_color) %>
<%=
time_field(:task, :started_at) %>
Dealing with Model Objects
These kind of helpers does
not use the sufix "_tag"
Ex: <%=
text_field(:person, :name) %>
Result:
<input id="person_name" name="person[name]" type="text" value="Henry"/>
Binding a Form to an Object
In controller
def
new
@article = Article.new
end
In view
<%=
form_for @article, url: {action: "create"}, html: {class:
"nifty_form"} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, size:
"60x12" %>
<%= f.submit "Create" %>
<%
end %>
If I have an association it
is possible to define a form to the associated object
<%= form_for
@person, url: {action: "create"} do |person_form| %>
<%= person_form.text_field :name %>
<%= fields_for @person.contact_detail do
|contact_details_form| %>
<%= contact_details_form.text_field
:phone_number %>
<% end %>
<% end %>
Result:
<form accept-charset="UTF-8" action="/people/create" class="new_person" id="new_person" method="post">
<input id="person_name" name="person[name]" type="text" />
<input id="contact_detail_phone_number" name="contact_detail[phone_number]" type="text" />
</form>
How do forms with PATCH, PUT, or DELETE methods work?
Some browsers don't have
PATCH, then Rails emulate this method using a hidden parameter in a POST search
form_tag(search_path, method:
"patch")
results:
<form accept-charset="UTF-8" action="/search" method="post">
<div style="margin:0;padding:0">
<input name="_method" type="hidden" value="patch" />
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
</div>
...
Select and option
The simplest way
<%=
select_tag(:city_id, '...') %>
ex:
<%=
options_for_select([['Lisbon', 1], ['Madrid', 2], ...]) %>
Together
<%=
select_tag(:city_id, options_for_select(...)) %>
ex:
<%=
options_for_select([['Lisbon', 1, {'data-size' => '2.8 million'}],
['Madrid', 2, {'data-size' => '3.2 million'}]], 2) %>
output:
<option value="1" data-size="2.8 million">Lisbon</option>
<option value="2" selected="selected" data-size="3.2 million">Madrid</option>
Select dealing with model
# controller:
@person
= Person.new(city_id: 2)
# view:
<%=
select(:person, :city_id, [['Lisbon', 1], ['Madrid', 2], ...]) %>
#OR
#
select on a form builder
<%=
person.select(:city_id, ...) %>
Options from a Array or
Collection
<% cities_array
= City.all.map { |city| [city.name, city.id] } %>
<%=
options_for_select(cities_array) %>
#Better
<%=
options_from_collection_for_select(City.all, :id, :name) %>
All together
<%=
collection_select(:person, :city_id, City.all, :id, :name) %>
Date and Time
Barebones Helpers
select_date,
select_time and select_datetime
<%= select_date
Date.today, prefix: :start_date %>
Equivalent Model Object
Helper
date_select,
time_select and datetime_select
<%= date_select
:person, :birth_date %>
#OR
<%=
person.date_select :birth_date %>
Uploading Files
The rendered form's encoding
MUST be set to "multipart/form-data"
With form_for it is
done automaticaly
With form_tag, you
must set it yourself
ex:
<%= form_for
@person do |f| %>
<%= f.file_field :picture %> ----->
params[:picture]
<% end %>
<%= form_tag({action:
:upload}, multipart: true) do %>
<%= file_field_tag 'picture' %>
---->params[:person][:picture]
<% end %>
Saving
Picture is save in
#{Rails.root}/public/uploads
def upload
uploaded_io = params[:person][:picture]
File.open(Rails.root.join('public',
'uploads', uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
end
end
With ajax
It is more complex
than other forms.
Parameters and conventions
HTML doesn't have any
structured data, just get pairs name-value
Basic Structure
#Input
<input id="person_name" name="person[name]" type="text" value="Henry"/>
#Params
{'person'
=> {'name' => 'Henry'}}
#Input
<input id="person_address_city" name="person[address][city]" type="text" value="New York"/>
#Params
{'person'
=> {'address' => {'city' => 'New York'}}}
Using Form Helper
<%= form_for
@person do |f| %>
<%= f.text_field :name %>
<% @person.addresses.each do |address|
%>
<%= f.fields_for address, index: address
do |address_form|%>
<%= address_form.text_field :city
%>
<% end %>
<% end %>
<% end %>
#Params
{'person'
=> {'name' => 'Bob', 'address' => {'23' => {'city' => 'Paris'},
'45' => {'city' => 'London'}}}}
Form to external resources
# It is possible to
pass an external token to access the external resource
<%= form_for
@invoice, url: external_url, authenticity_token: 'external_token' do |f| %>
Form contents
<% end %>
# OR
authenticity_token: false
Complex forms
#uses
accepts_nested_attributes_for
class Person <
ActiveRecord::Base
has_many :addresses
accepts_nested_attributes_for :addresses
end
class Address <
ActiveRecord::Base
belongs_to :person
end
This creates an
addresses_attributes= method
And creates a form with a
Person and its associates address
<%= form_for
@person do |f| %>
Addresses:
<%= f.fields_for :addresses do
|addresses_form| %>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind
%>
<%= addresses_form.label :street
%>
<%= addresses_form.text_field
:street %>
...
<% end %>
<%
end %>
Assinar:
Postagens (Atom)