Créer des méthodes dynamiquement (define_method)

Admettons que nous avons un tableau de rôles :

ROLES = %w(membre staff admin)

Et que pour chacun des rôles nous voulons faire une méthode similaire (nom du role + _percentage), plutôt que de toutes les écrire, on peut faire ça dans une boucle :

ROLES.each do |role|
  define_method (role + "_percentage").to_sym do
    # le code que je veux
  end
end

Et ainsi, tous les rôles auront la méthode _percentage :

membre_percentage
staff_percentage
admin_percentage
Posted in Rails | Leave a comment

Faire appel à une méthode nommé dynamiquement ( send() )

Admettons que dans un modèle nous avons les méthodes suivantes :

def membre_stats
  membre_stat
end

def staff_stats
  staff_stat
end

def admin_stats
  admin_stat
end

Si on veut appeler ses méthodes, il faudrait faire :

Object.membre_stats
Object.staff_stats
Object.admin_stats

On peut alors remplacer les 3 méthodes par :

def stats(role)
  send("#{role.to_s}_stat")
end

Et ensuite appeler via :

Object.stats(membre)
Object.stats(staff)
Object.stats(admin)
Posted in Rails | Leave a comment

Ruby Delegate

class Post
  belongs_to :user
end

class User
  has_many :posts
end

Si à partir de Post, on veut accéder au User.name sans avoir d’erreur si User n’est pas défini :

class Post
  belongs_to :user

  def name
    # renvoi null si user n'est pas défini
    user.try(:name)
  end
end

Tout le blog def name peut être remplacé par :

delegate :name, :to => :user, :allow_nil => true

De cette manière, le nom de l’utilisateur sera accessible via Post.name

Deuxième exemple :

class Post
  belongs_to :user
  belongs_to :image

  delegate :name, to: :user, prefix: true, allow_nil: true
  delegate :name, to: :image, prefix: true, allow_nil: true
end

class Image
  has_many :posts
end

class User
  has_many :posts
end

En rajoutant l’attribue prefix: true, je peux avoir plusieurs fois le « name », qui sera accessible cette fois via : Post.user_name et Post.image_name

Posted in Rails | Leave a comment

OwnCloud

Installation sous Ubuntu 12.04

apt-get update
apt-get upgrade

apt-get install apache2 php5 php5-json php5-gd php5-sqlite
curl libcurl3 libcurl3-dev php5-curl php5-common php-xml-parser
apt-get install sqlite

wget http://download.owncloud.org/releases/owncloud-4.0.4.tar.bz2
tar -xjf owncloud-4.0.4.tar.bz2
cp -r owncloud /var/www
chown -R www-data:www-data /var/www

service apache2 restart

Dans le fichier settings/js/users.js, commenter la ligne 216 (location.reload();)

Ensure that ‘AllowOverride’ is set to ‘All’ in the ‘Directory /var/www/’ section of your virtual host file

And run :

a2enmod rewrite
a2enmod headers
service apache2 restart
Posted in Autres | Leave a comment

Protéger l’accès à un environnement par mot de passe

Il suffit d’ajouter dans le fichier config/environments/staging.rb (dans le cas de ‘staging’)

config.middleware.insert_after(::Rack::Lock, "::Rack::Auth::Basic", "Staging") do |u, p|
    [u, p] == ['username', 'password']
  end
Posted in Installations & Bugs fix | Leave a comment

Changer de langue par un lien

/routes.rb

get 'locale/:locale' => "locale#locale", as: :locale

/app/controllers/locale_controller.rb

class LocaleController < ApplicationController

  def locale
    I18n.locale = params[:locale]
    redirect_to :back
  end
end

Faire le lien pour changer de langue par exemple :

- I18n.available_locales.each do |loc|
        = link_to loc.to_s, locale_path(loc)
Posted in Rails | Leave a comment

Internationalisation [subfolders]

Si on veut stocker les fichiers de traduction dans des sous-dossiers de /config/locales, il faut rajouter/modifier cette ligne dans le fichier /config/application.rb

config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

Aussi regarder ici : http://guides.rubyonrails.org/i18n.html#organization-of-locale-files

Posted in Rails | Leave a comment

Installer RVM sur OS X 10.7+

//Installez GCC (soit via Xcode, soit via https://github.com/kennethreitz/osx-gcc-installer)
//Désinstallez RVM si il est déjà installé
rvm implode
//Réinstallez RVM
bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
//Ajouter dans ~/.bash_profile
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"

Il est possible qu’avec OS X 10.7+ vous rencontriez une erreur de segmentation fault au moment d’un bundle install.
Cette erreur est liée au HTTPS présent dans votre Gemfile.
Pour pallier à cette erreur, voila comment il faut installer une version de Ruby :

rvm pkg install openssl
rvm remove 1.9.3
rvm install 1.9.3 --with-openssl-dir=$rvm_path/usr --with-gcc=clang
//Tester d'abord sans l'option --with-gcc

Sources :
http://www.stewgleadow.com/blog/2011/12/10/installing-rvm-on-os-x-lion/
http://www.rojotek.com/blog/2012/01/20/how-to-get-openssl-in-ruby-1-9-3-working-on-osx-10-7-fixing-the-segmentation-fault-with-ruby-openssl/

Posted in Installations & Bugs fix | Leave a comment

Skips

Avec CanCan il est possible de skiper le load_and_authorize_resource grâce à

skip_authorization_check

Il est également possible de skiper un before_filter grâce à :

skip_before_filter
Posted in Rails | Leave a comment

Cucumber [Ecriture d'une Feature]

Une Feature est un ensemble de Scénarios.
Une Feature peut avoir un  Background.
Un Scénario est un ensemble d’étape, devant se déroulé tel qu’il sera défini.
Un Background est un ensemble d’éléments, communs à tous les Scénario de la Feature.

Exemple de Feature (/features/news_items/news_admin.feature):

Feature:
  An admin should be able
  To administer the news items

  Background:
    Given I am an admin
    And there is 1 news category in the database
    And there is 1 news item in the database
  	When I go to the show news category page

  Scenario:
    Then I should see the news item title
    And I should see a link to "Edit"
    And I should see a link to "Delete"

  Scenario: Adding
    Given I should see a link to "New"
    When I go to the new news item page

    When I fill in the news item fields with valid info
    And I press "SAVE"

    And I should see the news item title
    And I should see a link to "Edit"
    And I should see a link to "Delete"

Une Feature possède tout d’abord un énoncé, qui sera affiché lors de l’exécution des tests.
Un Background et les Scenarios peuvent avoir un Titre (ici Adding pour le 2ème Scenario).

La syntaxe utilisée dans la description des steps (chaque étape d’un Scenario ou Background) ne peut pas être n’importe quoi, cette syntaxe est définie ailleurs.
Nous allons tout d’abord retrouver les steps propre à notre modèle (ici news_item).
Ces steps sont à trouver/écrire dans : /features/step_definitions/nom_du_model_steps.rb

Donc dans notre exemple  /features/step_definitions/news_items_steps.rb
Prenons un extrait de ce fichier :

When /^I fill in the news item fields with valid info$/ do
  step %{I fill in "news_item_title_fr" with "Titre"}
  step %{I fill in "news_item_body_fr" with "My content"}
  step %{I fill in "news_item_title_en" with "Title"}
  step %{I fill in "news_item_body_en" with "My content"}
end

Cette exemple (doit) ressembler à ce que nous avons dans notre Feature. Donc si on regarde bien, nous avons la ligne suivante dans le Scenario Adding :

When I fill in the news item fields with valid info

Cela veut donc dire, que quand dans notre Feature, il va se trouver devant cette ligne, il va chercher ce qu’elle fait, dans notre step_definitions.
Ici en l’occurrence, il remplit les champs du formulaire avec des valeurs définis dans le fichier.
Les noms de champs que nous voyons ici (news_item_title_fr par ex) correspond exactement à ce que donne le formulaire de la vue, car l’execution d’une Feature correspond en fait à la navigation dans le site, on lui dit « va sur cette page » « clique sur ce lien » « remplit ce champs ».

Voici maintenant le fichier de step_definitions des news_item en entier :

Then /^I should see the (?:news|news item) title$/ do
  step %{I should see "#{NewsItem.last.title}"}
end

Then /^I should see the (?:news|news item) body$/ do
  step %{I should see "#{@news_item.body}"}
end

When /^I fill in the news item fields with valid info$/ do
  step %{I fill in "news_item_title_fr" with "Titre"}
  step %{I fill in "news_item_body_fr" with "My content"}
  step %{I fill in "news_item_title_en" with "Title"}
  step %{I fill in "news_item_body_en" with "My content"}
end

Then /^the news item should be private$/ do
  NewsItem.last.public.should be_false
end

Then /^I should not see a link to new news item$/ do
  # This always sees a link to "New" because there's so many links to News etc on the page
  # step %{I should not see a link to "New"}
end

Then /^I should see a link to new news item$/ do
  step %{I should see a link to "New"}
end

Par défaut, ce fichier est vide, et c’est au développeur de l’écrire, donc de faire correspondre les étapes de ses Scenario, à une syntaxe compréhensible par le programme.

Comme on peut le voir, tout n’est pas défini (certain éléments présent dans notre Feature ne sont pas défini dans ce fichier steps_definition).
Cela s’explique car certaines étapes sont prédéfini dans d’autres fichiers tels que :
/features/step_definitions/web_steps.rb
/features/step_definitions/factory_magic_steps.rb
/features/step_definitions/only_n_steps.rb

Le fichier web_steps est un fichier fourni par Cucumber, il ne devrait donc pas y avoir à faire des modifications.
Les 2 autres fichiers sont a compléter également.

Pour finir, il faut savoir que pendant les tests, on ne travail pas réellement sur la base de données, mais sur un modèle qui s’appel FactoryGirl et qui permet de créer nos objets.
Les fichiers FactoryGirl sont stockés dans /spec/factories.
Dans notre cas : /spec/factories/news_item_factories.rb :

FactoryGirl.define do

  factory :news_item do
    title "My news"
    body "My Body"
    association :user
    release_at { Date.today - 1.week }
    valid_until { Date.today + 1.month }
    news_category
    public true
    publish true

    factory :private_news_item do
      public false
    end
  end  

end

La définition de ce fichier doit correspondre au vrai modèle, et ici on attribue également des valeurs par défaut, dans le cas où comme pour notre exemple, aucunes valeurs ne sont précisés.

 

Posted in Rails | Leave a comment