1require 'active_support/core_ext/digest/uuid'
 
2require 'postcode_sanitizer'
 
3require 'ipaddr'
 
4
  • Class "Signature" has 762 lines. It should have 300 or less. » roodi
5class Signature < ActiveRecord::Base
 
6  include PerishableTokenGenerator
 
7  include GeoipLookup
 
8
 
 9  has_perishable_token
 
10  has_perishable_token called: 'signed_token'
 
11  has_perishable_token called: 'unsubscribe_token'
 
 
13  ISO8601_TIMESTAMP = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\z/
 
 
15  PENDING_STATE = 'pending'
 
16  FRAUDULENT_STATE = 'fraudulent'
 
17  VALIDATED_STATE = 'validated'
 
18  INVALIDATED_STATE = 'invalidated'
 
 
20  STATES = [
 
21    PENDING_STATE, FRAUDULENT_STATE,
 
22    VALIDATED_STATE, INVALIDATED_STATE
 
23  ]
 
 
25  TIMESTAMPS = {
 
26    'government_response' => :government_response_email_at,
 
27    'debate_scheduled'    => :debate_scheduled_email_at,
 
28    'debate_outcome'      => :debate_outcome_email_at,
 
29    'petition_email'      => :petition_email_at
 
30  }
 
 
32  belongs_to :petition
 
33  belongs_to :invalidation
 
 
35  validates :state, inclusion: { in: STATES }
 
36  validates :name, presence: true, length: { maximum: 255 }
 
37  validates :email, presence: true, email: { allow_blank: true }, on: :create
 
38  validates :location_code, presence: true
 
39  validates :postcode, presence: true, postcode: true, if: :united_kingdom?
 
40  validates :postcode, length: { maximum: 255 }, allow_blank: true
 
41  validates :uk_citizenship, acceptance: true, unless: :persisted?, allow_nil: false
 
42  validates :constituency_id, length: { maximum: 255 }
 
 
44  attr_readonly :sponsor, :creator
 
 
46  before_create if: :email? do
 
47    self.uuid = generate_uuid
 
48    self.canonical_email = Domain.normalize(email)
 
 
50    if find_duplicate
 
51      raise ActiveRecord::RecordNotUnique, "Signature is not unique: #{name}, #{email}, #{postcode}"
 
52    end
 
 
54    if find_similar
 
55      raise ActiveRecord::RecordNotUnique, "Signature is not unique: #{name}, #{email}, #{postcode}"
 
56    end
 
57  end
 
 
59  before_destroy do
 
60    !creator?
 
61  end
 
 
63  after_destroy do
 
64    if validated?
 
65      now = Time.current
 
66      ConstituencyPetitionJournal.invalidate_signature_for(self, now)
 
67      CountryPetitionJournal.invalidate_signature_for(self, now)
 
68      petition.decrement_signature_count!(now)
 
69    end
 
70  end
 
 
72  class << self
 
73    def batch(id = 0, limit: 1000)
 
74      where(arel_table[:id].gt(id)).order(id: :asc).limit(limit)
 
75    end
 
 
77    def by_most_recent
 
78      order(created_at: :desc)
 
79    end
 
 
81    def column_name_for(timestamp)
 
82      TIMESTAMPS.fetch(timestamp)
 
83    rescue KeyError => e
 
84      raise ArgumentError, "Unknown petition email timestamp: #{timestamp.inspect}"
 
85    end
 
 
87    def destroy!(signature_ids)
 
88      signatures = find(signature_ids)
 
 
90      transaction do
 
91        signatures.each do |signature|
 
92          signature.destroy!
 
93        end
 
94      end
 
95    end
 
 
97    def duplicate(id, email)
 
98      where(arel_table[:id].not_eq(id).and(arel_table[:email].eq(email)))
 
 99    end
 
 
101    def duplicate_emails
 
102      unscoped.from(validated.select(:uuid).group(:uuid).having(arel_table[Arel.star].count.gt(1))).count
 
103    end
 
 
105    def pending_rate
 
106      (Rational(pending.count, total.count) * 100).to_d(2)
 
107    end
 
 
109    def similar(id, email)
 
110      where(canonical_email: email).where.not(id: id)
 
111    end
 
 
113    def for_domain(domain)
 
114      where("SUBSTRING(email FROM POSITION('@' IN email) + 1) = ?", domain[1..-1])
 
115    end
 
 
117    def for_email(email)
 
118      where("(REGEXP_REPLACE(LEFT(email, POSITION('@' IN email) - 1), '\\.|\\+.+', '', 'g') || SUBSTRING(email FROM POSITION('@' IN email)) = ?)", normalize_email(email))
 
119    end
 
 
121    def for_invalidating
 
122      where(state: [PENDING_STATE, VALIDATED_STATE])
 
123    end
 
 
125    def for_ip(ip)
 
126      where("inet(ip_address) <<= inet(?)", ip)
 
127    end
 
 
129    def for_name(name)
 
130      where(arel_table[:name].lower.eq(name.downcase))
 
131    end
 
 
133    def for_petition(id)
 
134      where(petition_id: id)
 
135    end
 
 
137    def for_postcode(postcode)
 
138      where(postcode: PostcodeSanitizer.call(postcode))
 
139    end
 
 
141    def for_sector(postcode)
 
142      where("LEFT(postcode, -3) = ?", PostcodeSanitizer.call(postcode)[0..-4])
 
143    end
 
 
145    def for_timestamp(timestamp, since:)
 
146      column = arel_table[column_name_for(timestamp)]
 
147      where(column.eq(nil).or(column.lt(since)))
 
148    end
 
 
150    def fraudulent
 
151      where(state: FRAUDULENT_STATE)
 
152    end
 
 
154    def fraudulent_domains
 
155      where(state: FRAUDULENT_STATE).
 
156      select("SUBSTRING(email FROM POSITION('@' IN email) + 1) AS domain").
 
157      group("SUBSTRING(email FROM POSITION('@' IN email) + 1)").
 
158      order("COUNT(*) DESC").
 
159      count(:all)
 
160    end
 
 
162    def invalidate!(signature_ids, now = Time.current, invalidation_id = nil)
 
163      signatures = find(signature_ids)
 
 
165      transaction do
 
166        signatures.each do |signature|
 
167          signature.invalidate!(now, invalidation_id)
 
168        end
 
169      end
 
170    end
 
 
172    def invalidated
 
173      where(state: INVALIDATED_STATE)
 
174    end
 
 
176    def missing_constituency_id(since: nil)
 
177      if since
 
178        uk.validated(since: since).where(constituency_id: nil)
 
179      else
 
180        uk.validated.where(constituency_id: nil)
 
181      end
 
182    end
 
 
184    def need_emailing_for(timestamp, since:)
 
185      validated.subscribed.for_timestamp(timestamp, since: since)
 
186    end
 
 
188    def pending
 
189      where(state: PENDING_STATE)
 
190    end
 
 
192    def total
 
193      where(state: [PENDING_STATE, VALIDATED_STATE])
 
194    end
 
 
196    def petition_ids_signed_since(timestamp)
 
197      validated(since: timestamp).distinct.pluck(:petition_id)
 
198    end
 
  • DuplicateMethodCall - calls 'scope.where(created_at: starts_at..ends_at)' 2 times » reek
  • TooManyStatements - has approx 20 statements » reek
  • Method name "search" cyclomatic complexity is 11. It should be 8 or less. » roodi
  • Method "search" has 39 lines. It should have 20 or less. » roodi
200    def search(query, options = {})
 
201      query  = query.to_s
 
202      state  = options[:state]
 
203      window = options[:window]
 
204      page   = [options[:page].to_i, 1].max
 
205      scope  = preload(:petition).by_most_recent
 
 
207      if state.in?(STATES)
 
208        scope = scope.where(state: state)
 
209      end
 
 
211      if window.present?
 
212        if window =~ ISO8601_TIMESTAMP
 
213          starts_at = window.in_time_zone.at_beginning_of_hour
 
214          ends_at = starts_at.advance(hours: 1)
 
215          scope = scope.where(created_at: starts_at..ends_at)
 
216        elsif window =~ /\A\d+\z/
 
217          starts_at = window.to_i.seconds.ago
 
218          ends_at = Time.current
 
219          scope = scope.where(created_at: starts_at..ends_at)
 
220        end
 
221      end
 
 
223      if ip_search?(query)
 
224        scope = scope.for_ip(query)
 
225      elsif domain_search?(query)
 
226        scope = scope.for_domain(query)
 
227      elsif email_search?(query)
 
228        scope = scope.for_email(query)
 
229      elsif petition_search?(query)
 
230        scope = scope.for_petition(query)
 
231      elsif postcode_search?(query)
 
232        scope = scope.for_postcode(query)
 
233      elsif sector_search?(query)
 
234        scope = scope.for_sector(query)
 
235      else
 
236        scope = scope.for_name(query)
 
237      end
 
 
239      scope.paginate(page: page, per_page: 50)
 
240    end
 
 
242    def creator
 
243      where(arel_table[:creator].eq(true))
 
244    end
 
 
246    def sponsors
 
247      where(arel_table[:sponsor].eq(true))
 
248    end
 
 
250    def subscribed
 
251      where(notify_by_email: true)
 
252    end
 
 
254    def fraudulent_domains(since: 1.hour.ago, limit: 20)
 
255      select("SUBSTRING(email FROM POSITION('@' IN email) + 1) AS domain").
 
256      where(arel_table[:created_at].gt(since)).
 
257      where(state: FRAUDULENT_STATE).
 
258      group("SUBSTRING(email FROM POSITION('@' IN email) + 1)").
 
259      order("COUNT(*) DESC").
 
260      limit(limit).
 
261      count(:all)
 
262    end
 
 
264    def fraudulent_ips(since: 1.hour.ago, limit: 20)
 
265      select(:ip_address).
 
266      where(arel_table[:created_at].gt(since)).
 
267      where(state: FRAUDULENT_STATE).
 
268      group(:ip_address).
 
269      order("COUNT(*) DESC").
 
270      limit(limit).
 
271      count(:all)
 
272    end
 
 
274    def trending_domains(since: 1.hour.ago, limit: 20)
 
275      select("SUBSTRING(email FROM POSITION('@' IN email) + 1) AS domain").
 
276      where(arel_table[:validated_at].gt(since)).
 
277      where(arel_table[:invalidated_at].eq(nil)).
 
278      group("SUBSTRING(email FROM POSITION('@' IN email) + 1)").
 
279      order("COUNT(*) DESC").
 
280      limit(limit).
 
281      count(:all)
 
282    end
 
 
284    def trending_ips(since: 1.hour.ago, limit: 20)
 
285      select(:ip_address).
 
286      where(arel_table[:validated_at].gt(since)).
 
287      where(arel_table[:invalidated_at].eq(nil)).
 
288      group(:ip_address).
 
289      order("COUNT(*) DESC").
 
290      limit(limit).
 
291      count(:all)
 
292    end
 
  • UncommunicativeVariableName - has the variable name 'h' » reek
  • UncommunicativeVariableName - has the variable name 'k' » reek
294    def trending_domains_by_petition(window, threshold = 5)
 
295      trending_domains = Hash.new { |h, k| h[k] = {} }
 
296      domain = "SUBSTRING(email FROM POSITION('@' IN email) + 1)"
 
 
298      where(validated_at: window)
 
299        .group(:petition_id, domain)
 
300        .having(count_star.gteq(threshold))
 
301        .order(:petition_id, count_star.desc)
 
302        .pluck(:petition_id, domain, count_star.to_sql)
 
303        .each_with_object(trending_domains) do |(petition_id, domain, count), hash|
 
304          hash[petition_id][domain] = count
 
305        end
 
306    end
 
  • TooManyStatements - has approx 7 statements » reek
  • UncommunicativeVariableName - has the variable name 'h' » reek
  • UncommunicativeVariableName - has the variable name 'k' » reek
308    def trending_ips_by_petition(window, threshold = 5, ignored_domains = [])
 
309      trending_ips = Hash.new { |h, k| h[k] = {} }
 
310      domain_not_in = "SUBSTRING(email FROM POSITION('@' IN email) + 1) NOT IN (?)"
 
 
312      scope = where(validated_at: window)
 
 
314      unless ignored_domains.empty?
 
315        scope = scope.where(domain_not_in, ignored_domains)
 
316      end
 
 
318      scope
 
319        .group(:petition_id, :ip_address)
 
320        .having(count_star.gteq(threshold))
 
321        .order(:petition_id, count_star.desc)
 
322        .pluck(:petition_id, :ip_address, count_star.to_sql)
 
323        .each_with_object(trending_ips) do |(petition_id, ip_address, count), hash|
 
324          hash[petition_id][ip_address] = count
 
325        end
 
326    end
 
 
328    def uk
 
329      where(location_code: "GB")
 
330    end
 
 
332    def unarchived
 
333      where(archived_at: nil)
 
334    end
 
 
336    def subscribe!(signature_ids)
 
337      signatures = find(signature_ids)
 
 
339      transaction do
 
340        signatures.each do |signature|
 
341          signature.update!(notify_by_email: true)
 
342        end
 
343      end
 
344    end
 
 
346    def unsubscribe!(signature_ids)
 
347      signatures = find(signature_ids)
 
 
349      transaction do
 
350        signatures.each do |signature|
 
351          if signature.creator?
 
352            raise RuntimeError, "Can't unsubscribe the creator signature"
 
353          elsif signature.pending?
 
354            raise RuntimeError, "Can't unsubscribe a pending signature"
 
355          else
 
356            signature.update!(notify_by_email: false)
 
357          end
 
358        end
 
359      end
 
360    end
 
 
362    def validate!(signature_ids, now = Time.current, force: false, request: nil)
 
363      signatures = find(signature_ids)
 
 
365      transaction do
 
366        signatures.each do |signature|
 
367          signature.validate!(now, force: force, request: request)
 
368        end
 
369      end
 
370    end
 
 
372    def validated(since: nil, upto: nil)
 
373      scope = where(state: VALIDATED_STATE)
 
374      scope = scope.where(validated_at.gt(since)) if since
 
375      scope = scope.where(validated_at.lteq(upto)) if upto
 
376      scope
 
377    end
 
 
379    def validated_count(timestamp, upto)
 
380      validated(since: timestamp, upto: upto).pluck(count_star.to_sql).first
 
381    end
 
 
383    def validated_count_by_location_code(timestamp, upto)
 
384      validated(since: timestamp, upto: upto).group(:location_code).pluck(:location_code, count_star.to_sql)
 
385    end
 
 
387    def validated_count_by_constituency_id(timestamp, upto)
 
388      validated(since: timestamp, upto: upto).group(:constituency_id).pluck(:constituency_id, count_star.to_sql)
 
389    end
 
 
391    def validated?(id)
 
392      where(id: id).where(validated_at.not_eq(nil)).exists?
 
393    end
 
 
395    private
 
  • UncommunicativeVariableName - has the variable name 'e' » reek
397    def ip_search?(query)
 
398      IPAddr.new(query)
 
399    rescue IPAddr::InvalidAddressError => e
 
400      false
 
401    end
 
 
403    def domain_search?(query)
 
404      query.starts_with?('@')
 
405    end
 
 
407    def email_search?(query)
 
408      query.include?('@')
 
409    end
 
 
411    def petition_search?(query)
 
412      query =~ /\A\d+\z/
 
413    end
 
 
415    def postcode_search?(query)
 
416      PostcodeSanitizer.call(query) =~ PostcodeValidator::PATTERN
 
417    end
 
 
419    def sector_search?(query)
 
420      PostcodeSanitizer.call(query) =~ /\A[A-Z]{1,2}[0-9][0-9A-Z]?XXX\z/
 
421    end
 
 
423    def validated_at
 
424      arel_table[:validated_at]
 
425    end
 
 
427    def count_star
 
428      arel_table[Arel.star].count
 
429    end
 
 
431    def max_validated_at
 
432      arel_table[:validated_at].maximum.to_sql
 
433    end
 
 
435    def normalize_email(email)
 
436      "#{normalize_user(email)}@#{normalize_domain(email)}"
 
437    end
 
 
439    def normalize_user(email)
 
440      email.split("@").first.split("+").first.tr(".", "").downcase
 
441    end
 
 
443    def normalize_domain(email)
 
444      email.split("@").last.downcase
 
445    end
 
446  end
 
 
448  attr_accessor :uk_citizenship
 
  • DuplicateMethodCall - calls 'signatures.first' 2 times » reek
450  def find_duplicate
 
451    return nil unless petition
 
 
453    signatures = petition.signatures.duplicate(id, email)
 
454    return signatures.first if signatures.many?
 
  • Found = in conditional. It should probably be an == » roodi
456    if signature = signatures.first
 
457      if sanitized_name == signature.sanitized_name
 
458        signature
 
459      elsif postcode != signature.postcode
 
460        signature
 
461      end
 
462    end
 
463  end
 
 
465  def find_duplicate!
 
466    find_duplicate || find_similar || (raise ActiveRecord::RecordNotFound, "Signature not found: #{name}, #{email}, #{postcode}")
 
467  end
 
  • DuplicateMethodCall - calls 'signatures.first' 2 times » reek
469  def find_similar
 
470    return nil unless petition
 
 
472    signatures = petition.signatures.similar(id, canonical_email)
 
473    return signatures.first if signatures.many?
 
  • Found = in conditional. It should probably be an == » roodi
475    if signature = signatures.first
 
476      if sanitized_name == signature.sanitized_name
 
477        signature
 
478      elsif postcode != signature.postcode
 
479        signature
 
480      end
 
481    end
 
482  end
 
 
484  def name=(value)
 
485    super(value.to_s.strip)
 
486  end
 
 
488  def email=(value)
 
489    super(value.to_s.strip.downcase)
 
490  end
 
 
492  def postcode=(value)
 
493    super(PostcodeSanitizer.call(value))
 
494  end
 
 
496  def sanitized_name
 
497    name.to_s.parameterize
 
498  end
 
 
500  def pending?
 
501    state == PENDING_STATE
 
502  end
 
 
504  def fraudulent?
 
505    state == FRAUDULENT_STATE
 
506  end
 
 
508  def validated?
 
509    state == VALIDATED_STATE
 
510  end
 
 
512  def invalidated?
 
513    state == INVALIDATED_STATE
 
514  end
 
 
516  def subscribed?
 
517    validated? && !unsubscribed?
 
518  end
 
 
520  def unsubscribed?
 
521    notify_by_email == false
 
522  end
 
 
524  def fraudulent!(now = Time.current)
 
525    retry_lock do
 
526      if pending?
 
527        update_columns(state: FRAUDULENT_STATE, updated_at: now)
 
528      end
 
529    end
 
530  end
 
  • BooleanParameter - has boolean parameter 'force' » reek
  • BooleanParameter - has boolean parameter 'force' » reek
  • ControlParameter - is controlled by argument 'force' » reek
  • LongParameterList - has 4 parameters » reek
  • TooManyStatements - has approx 16 statements » reek
  • Method name "validate!" cyclomatic complexity is 13. It should be 8 or less. » roodi
  • Method "validate!" has 45 lines. It should have 20 or less. » roodi
532  def validate!(now = Time.current, force: false, request: nil)
 
533    update_signature_counts = false
 
534    new_constituency_id = nil
 
 
536    unless constituency_id?
 
537      if united_kingdom? && postcode?
 
538        new_constituency_id = constituency.try(:external_id)
 
539      end
 
540    end
 
  • Block cyclomatic complexity is 7. It should be 4 or less. » roodi
542    retry_lock do
 
543      if force || pending?
 
544        update_signature_counts = true
 
545        petition.validate_creator!(now) unless creator?
 
 
547        attributes = {
 
548          number:       petition.signature_count + 1,
 
549          state:        VALIDATED_STATE,
 
550          validated_at: now,
 
551          invalidation_id: nil,
 
552          invalidated_at:  nil,
 
553          updated_at:   now
 
554        }
 
 
556        if request
 
557          attributes[:validated_ip] = request.remote_ip
 
558        end
 
 
560        if new_constituency_id
 
561          attributes[:constituency_id] = new_constituency_id
 
562        end
 
 
564        unless signed_token?
 
565          attributes[:signed_token] = Authlogic::Random.friendly_token
 
566        end
 
 
568        update_columns(attributes)
 
569      end
 
570    end
 
 
572    if update_signature_counts
 
573      @just_validated = true
 
574    end
 
 
576    if inline_updates? && update_signature_counts
 
577      last_signed_at = petition.last_signed_at
 
578      petition.increment_signature_count!(now)
 
 
580      ConstituencyPetitionJournal.increment_signature_counts_for(petition, last_signed_at)
 
581      CountryPetitionJournal.increment_signature_counts_for(petition, last_signed_at)
 
582    end
 
583  end
 
 
585  def just_validated?
 
586    defined?(@just_validated) ? @just_validated : false
 
587  end
 
 
589  def validated_before?(timestamp)
 
590    validated? && validated_at < timestamp
 
591  end
 
 
593  def reload(*)
 
594    super.tap { @just_validated = false }
 
595  end
 
  • TooManyStatements - has approx 7 statements » reek
597  def invalidate!(now = Time.current, invalidation_id = nil)
 
598    update_signature_counts = false
 
 
600    retry_lock do
 
601      if validated?
 
602        update_signature_counts = true
 
603      end
 
 
605      update_columns(
 
606        state:           INVALIDATED_STATE,
 
607        notify_by_email: false,
 
608        invalidation_id: invalidation_id,
 
609        invalidated_at:  now,
 
610        updated_at:      now
 
611      )
 
612    end
 
 
614    if update_signature_counts
 
615      ConstituencyPetitionJournal.invalidate_signature_for(self, now)
 
616      CountryPetitionJournal.invalidate_signature_for(self, now)
 
617      petition.decrement_signature_count!(now)
 
618    end
 
619  end
 
 
621  def mark_seen_signed_confirmation_page!
 
622    update seen_signed_confirmation_page: true
 
623  end
 
  • UncommunicativeVariableName - has the variable name 'e' » reek
625  def save(*args)
 
626    super
 
627  rescue ActiveRecord::RecordNotUnique => e
 
628    if creator?
 
629      errors.add(:name, :already_signed, name: name, email: email) and return false
 
630    else
 
631      raise e
 
632    end
 
633  end
 
  • ControlParameter - is controlled by argument 'token' » reek
  • TooManyStatements - has approx 6 statements » reek
635  def unsubscribe!(token)
 
636    if unsubscribed?
 
637      errors.add(:base, "Already Unsubscribed")
 
638    elsif unsubscribe_token != token
 
639      errors.add(:base, "Invalid Unsubscribe Token")
 
640    else
 
641      update(notify_by_email: false)
 
642    end
 
643  end
 
 
645  def already_unsubscribed?
 
646    errors[:base].include?("Already Unsubscribed")
 
647  end
 
 
649  def invalid_unsubscribe_token?
 
650    errors[:base].include?("Invalid Unsubscribe Token")
 
651  end
 
 
653  def constituency
 
654    if constituency_id?
 
655      @constituency ||= Constituency.find_by_external_id(constituency_id)
 
656    elsif united_kingdom?
 
657      @constituency ||= Constituency.find_by_postcode(postcode)
 
658    end
 
659  end
 
 
661  def signed_token
 
662    super || generate_and_save_signed_token
 
663  end
 
 
665  def get_email_sent_at_for(timestamp)
 
666    self[column_name_for(timestamp)]
 
667  end
 
 
669  def set_email_sent_at_for(timestamp, to: Time.current)
 
670    update_column(column_name_for(timestamp), to)
 
671  end
 
 
673  def account
 
674    Mail::Address.new(email).local
 
675  rescue Mail::Field::ParseError
 
676    nil
 
677  end
 
 
679  def domain
 
680    Mail::Address.new(email).domain
 
681  rescue Mail::Field::ParseError
 
682    nil
 
683  end
 
 
685  def rate(window = 5.minutes)
 
686    period = Range.new(created_at - window, created_at)
 
687    petition.signatures.where(ip_address: ip_address, created_at: period).count
 
688  end
 
 
690  def update_uuid
 
691    update_column(:uuid, generate_uuid)
 
692  end
 
 
694  def update_canonical_email
 
695    update_column(:canonical_email, Domain.normalize(email))
 
696  end
 
 
698  def number
 
699    super || petition.signature_count + 1
 
700  end
 
 
702  def email_threshold_reached?
 
703    email_count >= 5
 
704  end
 
 
706  def united_kingdom?
 
707    location_code == 'GB'
 
708  end
 
709  alias_method :uk?, :united_kingdom?
 
 
711  def update_all(updates)
 
712    self.class.unscoped.where(id: id).update_all(updates)
 
713  end
 
 
715  def location
 
716    if postcode?
 
717      "#{formatted_postcode}, #{location_code}"
 
718    else
 
719      location_code
 
720    end
 
721  end
 
 
723  def form_duration
 
724    form_requested_at? ? created_at - form_requested_at : 0
 
725  end
 
 
727  def form_token_reused?
 
728    self.class.where(form_token: form_token).count > 1
 
729  end
 
 
731  private
 
 
733  def formatted_postcode
 
734    if united_kingdom?
 
735      postcode.gsub(/\A([A-Z0-9]+?)([A-Z0-9]{3})\z/, "\\1 \\2")
 
736    else
 
737      postcode
 
738    end
 
739  end
 
  • UtilityFunction - doesn't depend on instance state (maybe move it to another class?) » reek
741  def inline_updates?
 
742    ENV["INLINE_UPDATES"] == "true"
 
743  end
 
 
745  def generate_uuid
 
746    Digest::UUID.uuid_v5(Digest::UUID::URL_NAMESPACE, "mailto:#{email}")
 
747  end
 
 
749  def generate_and_save_signed_token
 
750    token = Authlogic::Random.friendly_token
 
 
752    retry_lock do
 
753      if signed_token?
 
754        token = read_attribute(:signed_token)
 
755      else
 
756        update_column(:signed_token, token)
 
757      end
 
758    end
 
 
760    token
 
761  end
 
  • UncommunicativeVariableName - has the variable name 'e' » reek
763  def column_name_for(timestamp)
 
764    self.class.column_name_for(timestamp)
 
765  end
 
  • TooManyStatements - has approx 8 statements » reek
  • UncommunicativeVariableName - has the variable name 'e' » reek
767  def retry_lock
 
768    retried = false
 
 
770    begin
 
771      with_lock { yield }
 
772    rescue PG::InFailedSqlTransaction => e
 
773      if retried
 
774        raise e
 
775      else
 
776        retried = true
 
777        self.class.connection.clear_cache!
 
778        retry
 
779      end
 
780    end
 
781  end
 
782end