web-dev-qa-db-fra.com

compteur d'accès simple pour les pages vues en rails

J'ai trouvé plusieurs solutions à ce problème, par exemple railstat de ce post:

Pages vues dans Rails

J'ai un tas d'articles et de critiques dont je voudrais un compteur d'accès filtré par des adresses IP uniques. Exactement comme Stackoverflow le fait pour ce post. Mais je ne me soucie pas vraiment d'une solution telle que railstat lorsque google analytics le fait déjà pour moi et inclut beaucoup de code, en gardant une trace d'adresses IP uniques, etc. Ma pensée actuelle est d'utiliser Garb ou d'autres analytics plugin pour extraire les statistiques des pages si elles sont plus anciennes que 12 heures de mise à jour d'une table, mais j'ai également besoin d'un cache_column.

Je suppose que vous pouvez extraire les statistiques d'Analytics pour une page particulière et qu'elles mettent à jour leurs statistiques toutes les 12 heures?

Je me demande s'il y a des raisons pour lesquelles ce serait une mauvaise idée, ou si quelqu'un a une meilleure solution?

Merci

37
holden

[~ # ~] mise à jour [~ # ~]

Le code de cette réponse a été utilisé comme base pour http://github.com/charlotte-Ruby/impressionist Essayez-le


Il vous faudrait probablement moins de temps pour coder cela dans votre application que pour extraire les données d'Analytics à l'aide de leur API. Ces données seraient probablement plus précises et vous n'auriez pas à vous fier à une dépendance externe .. vous auriez également les statistiques en temps réel au lieu d'attendre 12 heures sur les données Analytics. request.remote_ip fonctionne plutôt bien. Voici une solution utilisant le polymorphisme. Veuillez noter que ce code n'a pas été testé, mais il devrait être proche.

Créez un nouveau modèle/migration pour stocker vos pages vues (impressions):

class Impressions < ActiveRecord::Base
  belongs_to :impressionable, :polymorphic=>true 
end

class CreateImpressionsTable < ActiveRecord::Migration
  def self.up
    create_table :impressions, :force => true do |t|
      t.string :impressionable_type
      t.integer :impressionable_id
      t.integer :user_id
      t.string :ip_address
      t.timestamps
    end
  end

  def self.down
    drop_table :impressions
  end
end

Ajoutez une ligne à votre modèle d'article pour l'association et ajoutez une méthode pour renvoyer le nombre d'impressions:

class Article < ActiveRecord::Base
  has_many :impressions, :as=>:impressionable

  def impression_count
    impressions.size
  end

  def unique_impression_count
    # impressions.group(:ip_address).size gives => {'127.0.0.1'=>9, '0.0.0.0'=>1}
    # so getting keys from the hash and calculating the number of keys
    impressions.group(:ip_address).size.keys.length #TESTED
  end
end

Créez un before_filter pour articles_controller sur l'action show:

before_filter :log_impression, :only=> [:show]

def log_impression
  @article = Article.find(params[:id])
  # this assumes you have a current_user method in your authentication system
  @article.impressions.create(ip_address: request.remote_ip,user_id:current_user.id)
end

Ensuite, vous appelez simplement le unique_impression_count dans votre vue

<%[email protected]_impression_count %>

Si vous l'utilisez sur un tas de modèles, vous voudrez peut-être DRY le mettre en place. Mettez le def avant_filter dans application_controller et utilisez quelque chose de dynamique comme:

impressionable_class = controller_name.gsub("Controller","").constantize
impressionable_instance = impressionable_class.find(params[:id])
impressionable_instance.impressions.create(ip_address:request.remote_ip,user_id:current_user.id)

Et déplacez également le code du modèle Article vers un module qui sera inclus dans ActiveRecord :: Base. Vous pouvez mettre le send include dans une config/initializer .. ou si vous voulez devenir fou, il suffit de transformer le tout en un moteur Rails, afin que vous puissiez le réutiliser sur d'autres applications.

module Impressionable
  def is_impressionable
    has_many :impressions, :as=>:impressionable
    include InstanceMethods
  end
  module InstanceMethods
    def impression_count
      impressions.size
    end

    def unique_impression_count
      impressions.group(:ip_address).size
    end
  end
end

ActiveRecord::Base.extend Impressionable
93
johnmcaliley