[ rails ] Pundit — Validation

Overview

Minimal authorization through OO design and pure Ruby classes

protect_from_forgery with: :null_session

rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

private

def user_not_authorized
flash[:alert] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end

/app/policies/post_policy.rb

class PostPolicy < ApplicationPolicy

attr_reader :user, :post

def initialize(user, record)
@user = user
@record = record
end
def update?
user.admin? or not record.published?
end
end
@post = Post.find(params[:id])
authorize @post   # init
if @post.update(post_params) # call update? in policy
redirect_to @post
else
render :edit
end
  • The class has the same name as some kind of model class, only suffixed with the word “Policy”.
  • The first argument is a user. In your controller, Pundit will call the current_user method to retrieve what to send into this argument.
  • The second argument is some kind of model object, whose authorization you want to check. This does not need to be an ActiveRecord or even an ActiveModel object, it can be anything really.

Tests for your policies in RSpec

Require pundit/rspec in your spec_helper.rb

Then put your policy specs in spec/policies.

 

ref : https://github.com/elabs/pundit,

http://www.rubydoc.info/gems/pundit

[ rails ] ActionController Parameters — prevent attributes from mass update

Allows you to choose which attributes should be whitelisted for mass updating and thus prevent accidentally exposing that which shouldn’t be exposed.

  • require is used to mark parameters as required.
  • permit is used to set the parameter as permitted and limit which attributes should be allowed for mass updating
params = ActionController::Parameters.new({
person: {
name: 'Francesco',
age: 22,
role: 'admin'
}
})

permitted = params.require(:person).permit(:name, :age)
permitted # => {"name"=>"Francesco", "age"=>22}
permitted.class # => ActionController::Parameters
permitted.permitted? # => true

Person.first.update!(permitted)
# => #<Person id: 1, name: "Francesco", age: 22, role: "user">

ref : http://api.rubyonrails.org/classes/ActionController/Parameters.html

[ ruby ] Symbol v.s. String

Prefixed with a colon. Examples – :action, :line_items

  • Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.
puts "string".object_id
puts "string".object_id
puts :symbol.object_id
puts :symbol.object_id

Finding all symbol at this moment.

Symbol.all_symbols

Example : 

know_ruby = :yes
if know_ruby == :yes
puts 'You are a Rubyist'
else
puts 'Start learning Ruby'
end

is better than

know_ruby = 'yes'
if know_ruby == 'yes'
puts 'You are a Rubyist'
else
puts 'Start learning Ruby'
end

Every mention of ‘yes’ creates a new object stored separately in memory, whereas symbols are single reference values that are only initialized once.

Using symbol as Hash Key

h = {:nickname => 'IndianGuru', :language => 'Marathi', :lastname => 'Talim'}

or

h = {nickname: 'IndianGuru', language: 'Marathi', lastname: 'Talim'}

An exception to the shorter {symbol: value} syntax is when you would like to use a numeric key:

hash = {1: 'one'} # will not work
hash = {1 => 'one'} # will work 

ref : http://rubylearning.com/satishtalim/ruby_symbols.html,

http://rubylearning.com/satishtalim/ruby_hashes.html,

http://rubylearning.com/blog/2007/11/26/akitaonrails-on-ruby-symbols/

[ ruby ] %i( ) notation

To help reduce escape character.

Example

=> %{Hello World}
=> %<Hello World>
=> %(Hello World)
=> %[Hello World]
=> %?Hello World?
=> %?Hello?World? #This fails
=> %?Hello\?World? #This is fine because the inner ? is escaped
=> %<Hello < World> #This will break because the internal brackets arent' balanced
=> %{Hello {there} World} #This works just fine!

Decorating the %

q string
Q interpolated string
w array of strings
W interpolated array of strings

=> num = 2
=> %q{1+1=#{num}} #evaluates to "1+1=\#{num}"
=> %Q{1+1=#{num}} #evaluates to "1+1=2"
=> %w{This is an array} #evaluates to ["this", "is", "an", "array"]

%r[ ] # Interpolated Regexp (flags can appear after the closing delimiter)
%i[ ] # Non-interpolated Array of symbols, separated by whitespace
%I[ ] # Interpolated Array of symbols, separated by whitespace

%x[ ] # Interpolated shell command

%i{foo bar} # => [:foo, :bar]

ref : https://mikeyhogarth.wordpress.com/2011/11/24/notation-for-ruby-literals/,

http://stackoverflow.com/questions/8816877/is-there-a-literal-notation-for-an-array-of-symbols

[ rails ] friendly_id

What is friendly_id ?

With FriendlyId, it’s easy to make your application use URLs like:

http://example.com/states/washington

instead of:

http://example.com/states/4323454

 

class User < ApplicationRecord
include FriendlyId
friendly_id :name, use: :slugged
end

User.create! name: "Joe Schmoe"

# Change User.find to User.friendly.find in your controller
User.friendly.find(params[:id])

use: :slugged = look for a slug column in the database’s articles table

Unique Slugs by Scope

Generate unique slugs within a scope.

Example

two restaurants in different cities to have the slug
+joes-diner+.
Please do note that you must drop the uniqueness constraint on the slug’s
column in the database when you’re scoping the slug.

class Restaurant < ActiveRecord::Base
extend FriendlyId
belongs_to :city
friendly_id :name, :use => :scoped, :scope => :city
end

class City < ActiveRecord::Base
extend FriendlyId
has_many :restaurants
friendly_id :name, :use => :slugged
end

City.friendly.find("seattle").restaurants.friendly.find("joes-diner")
City.friendly.find("chicago").restaurants.friendly.find("joes-diner")

Without :scoped in this case, one of the restaurants would have the slug joes-diner and the other would have joes-diner-f9f3789a-daec-4156-af1d-fab81aa16ee5.

class Cuisine < ActiveRecord::Base
extend FriendlyId
has_many :restaurants
friendly_id :name, :use => :slugged
end

class City < ActiveRecord::Base
extend FriendlyId
has_many :restaurants
friendly_id :name, :use => :slugged
end

class Restaurant < ActiveRecord::Base
extend FriendlyId
belongs_to :city
friendly_id :name, :use => :scoped, :scope => [:city, :cuisine]
end

ref : http://norman.github.io/friendly_id/file.Guide.html, https://github.com/norman/friendly_id#rails-quickstart,

http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=asciicast,

http://ruby.zigzo.com/2011/10/08/how-to-use-the-friendly_id-gem-w-sti-models/,

https://github.com/norman/friendly_id/issues/167

 

[ rails ] ActiveRecord enum

class Conversation < ActiveRecord::Base

enum status: [ :active, :archived ]

end

&nbsp;

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status # => "archived"

# conversation.status = 1
conversation.status = "archived"

conversation.status = nil
conversation.status.nil? # => true
conversation.status # => nil

[ rails ] ActiveRecord default_scope, scope

default_scope

default_scope{ order(created_at :desc)}

ref : http://apidock.com/rails/ActiveRecord/Base/default_scope/class

scope

scope :created_before, ->(time) { where("created_at < ?", time) }
scope :created_before, lambda { |time|
where("created_at &lt; ?", time)
}

scope can be chainable

scope :published, -> { where(published: true) }
scope :published_and_commented, -> { published.where("comments_count > 0") }

ref : http://guides.rubyonrails.org/active_record_querying.html,

http://stackoverflow.com/questions/8476627/what-do-you-call-the-operator-in-ruby