merit-gem / merit

Reputation engine for Rails apps
Other
1.53k stars 197 forks source link

Add/Subtract points: NO Method error #333

Closed bhavyabh closed 5 years ago

bhavyabh commented 5 years ago

Hi Tute,

We are trying to subtract points via rails console using the query 'User.email.where("email@email.com").subtract_points(#)'. This query stopped working when we inverted the relationship between users and profiles(Before profiles table referencing the users table via a user_id column, now we changed to users table referencing the profiles table via a profile_id). The query throws undefined method 'subtract_points' error.

Hope you can help us to solve it. Thank you! cc:@monroemann

tute commented 5 years ago

Please paste the contents of your User and Profile models so I can see what is happening. Also, the full error message please. Thanks!

bhavyabh commented 5 years ago

Tute, Thank you very much for your quick reply.

Here is contents of profile.rb



  mount_uploader :avatar, AvatarUploader

  include PgSearch
    multisearchable :against => [:slack_user_name]

  has_one :avatar
  has_one :user

  belongs_to :current_country, class_name: 'Country'
  belongs_to :origin_country, class_name: 'Country'

  belongs_to :large_city
  belongs_to :geographic_area

  has_many :profiles_native_languages, :dependent => :destroy
  has_many :native_languages, through: :profiles_native_languages
  # accepts_nested_attributes_for :profiles_native_languages

  has_many :profiles_studying_languages, :dependent => :destroy
  has_many :studying_languages, through: :profiles_studying_languages
  # accepts_nested_attributes_for :profiles_studying_languages

  has_many :profiles_dive_lists, :dependent => :destroy
  has_many :dive_lists, through: :profiles_dive_lists
  # accepts_nested_attributes_for :profiles_dive_lists

  has_many :checklist_item_completions
  has_many :checklist_items, through: :checklist_item_completions
  accepts_nested_attributes_for :checklist_items

  has_many :profiles_pursuing_dives, :dependent => :destroy
  has_many :pursuing_dives, through: :profiles_pursuing_dives
  accepts_nested_attributes_for :profiles_pursuing_dives

  validates :current_country_id, presence: true
  validates :origin_country_id, presence: true
  validates :large_city_id, presence: true

  validates :geographic_area_id, presence: false
  validates :current_city, presence: true
  #validates :slack_user_name, presence: false, uniqueness: true
  validates :avatar, presence: false
  validates :native_language_ids, presence: true

  before_update :change_large_city

  scope :native_language_speakers, ->(group) { joins(:profiles_native_languages).joins(:native_languages).where("native_languages.group_id = ?", group) }
  scope :studying_language_speakers, ->(group) { joins(:profiles_studying_languages).joins(:studying_languages).where("studying_languages.group_id = ?", group) }

  def completed_profile?
    self.current_country_id.present? &&
    self.origin_country_id.present? &&
    self.large_city_id.present? &&
    self.current_city.present? &&
    self.native_language_ids.present?
  end

  def can_pursue_new_dives?
    pursuing_dives.size < 2 || user.unlimited_dives? || user.all_access? || user.staff?
  end

  # change user group on large city changed on profile
  def change_large_city
    return unless large_city_id_changed?
    last_city = LargeCity.find(self.large_city_id_was)
    current_city = LargeCity.find(self.large_city_id)

    last_city_group = Group.find_by(name: last_city.name)
    current_city_group = Group.find_by(name: current_city.name)

    if (self.user.in_group?(last_city_group))
      last_city_group.users.delete(self.user)
      if !(self.user.in_group?(current_city_group))
      current_city_group.add(self.user)
      end
    end
  end

end```
bhavyabh commented 5 years ago

user.rb


class User < ApplicationRecord
  has_merit

  extend FriendlyId
  friendly_id :default_slug, use: :slugged
  after_create :remake_slug

  #Automatically adds each new user to the BD - General Chatroom upon joining
  after_create do
    general_chat = Chatroom.find(1)
    general_chat.chatroom_users.where(user_id: id).first_or_create
  end

  include PgSearch
    multisearchable :against => [:email, :first_name, :last_name]

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, :confirmable,
         :recoverable, :rememberable, :trackable, :validatable

  # Email confirmation is turned OFF.  To turn on, see protected section at bottom.

  # Strong Passwords
  # include ActiveModel::Validations

  # Basic usage.  Defaults to minimum entropy of 18 and no dictionary checking
  # validates :password, password_strength: true

  # Minimum entropy can be specified as min_entropy
  #validates :password, password_strength: {min_entropy: 40}
  # Specifies that we want to use dictionary checking
  #validates :password, password_strength: {use_dictionary: true}
  # Specifies the minimum size of things that should count as words.  Defaults to 4.
  #validates :password, password_strength: {use_dictionary: true, min_word_length: 6}
  # Specifies that we want to use dictionary checking and adds 'other', 'common', and 'words' to the dictionary we are checking against.
  #validates :password, password_strength: {extra_dictionary_words: ['other', 'common', 'words'], use_dictionary: true}
  # You can also specify a method name to pull the extra words from
  #validates :password, password_strength: {extra_dictionary_words: :my_extra_words, use_dictionary: true}
  # Alternative way to request password strength validation on a field
  #validates_password_strength :password

  validates :email, confirmation: true
  validates :email_confirmation, presence: true, on: :create

  validates_acceptance_of :tos_accepted, message: "You must accept the Terms & Conditions in order to continue."

  belongs_to :profile, :dependent => :destroy

  has_many :posts, :class_name => "Post", :foreign_key => "author_id", :dependent => :destroy
  has_many :comments, :dependent => :destroy
  has_many :notifications, foreign_key: :recipient_id

  has_many :chatroom_users, :dependent => :destroy
  has_many :chatrooms, through: :chatroom_users
  has_many :chat_messages, :dependent => :destroy
  belongs_to :referred_by, class_name: "User", optional: true
  has_many :referred_users, class_name: "User", foreign_key: :referred_by_id
  before_create :set_referral_code
  validates :referral_code, uniqueness: true

  belongs_to :membership_level, optional: true

  groupify :named_group_member
  groupify :group_member

  acts_as_messageable

  before_create :set_recruit_level

  def set_recruit_level
    level = MembershipLevel.find_by(name: 'Recruit')
    self.membership_level_id = level.id if level.present?
  end

  before_save :capitalize_names

  def capitalize_names
    self.first_name = first_name.titleize
    self.last_name = last_name.titleize
  end

  def full_name
    "#{first_name} #{last_name}"
  end

  # As users join, the first "Mike Love" will be given a slug of mikelove, 
  # then the second "Mike Love" will be given a slug of mikelove1, then mikelove2, etc.
  # and after 9, it will start using the member's user id instead  
  def default_slug    
    [
      "#{first_name}#{last_name}",      
      ["#{first_name}#{last_name}1"],
      ["#{first_name}#{last_name}2"],
      ["#{first_name}#{last_name}3"],
      ["#{first_name}#{last_name}4"],
      ["#{first_name}#{last_name}5"],            
      ["#{first_name}#{last_name}6"],
      ["#{first_name}#{last_name}7"],
      ["#{first_name}#{last_name}8"],
      ["#{first_name}#{last_name}9"],
      ["#{first_name}#{last_name}#{id}"]
    ]
  end

  def remake_slug
    self.update_attribute(:slug, nil)
    self.save!
  end

  def self.update_membership_level(user)
      level1 = Group.with_member(user).as('Level 1').size
      level2 = Group.with_member(user).as('Level 2').size
      level3 = Group.with_member(user).as('Level 3').size
      level4 = Group.with_member(user).as('Level 4').size
      level5 = Group.with_member(user).as('Level 5').size
      elite = Group.with_member(user).as('Elite').size

      update_level = 'Recruit'
      if level1 >= 5 and level2 < 5 and level3 < 5 and level4 < 5 and level5 < 5 and elite < 5
        update_level = 'Level 1'
      elsif level1 >= 10 and level2 >= 5 and level3 < 5 and level4 < 5 and level5 < 5 and elite < 5
        update_level = 'Level 2'
      elsif level1 >= 15 and level2 >= 10 and level3 >= 5 and level4 < 5 and level5 < 5 and elite < 5
        update_level = 'Level 3'
      elsif level1 >= 20 and level2 >= 15 and level3 >= 10 and level4 >= 5 and level5 < 5 and elite < 5
        update_level = 'Level 4'
      elsif level1 >= 25 and level2 >= 20 and level3 >= 15 and level4 >= 10 and level5 >= 5 and elite < 5
        update_level = 'Level 5' 
      elsif level1 >= 30 and level2 >= 25 and level3 >= 20 and level4 >= 15 and level5 >= 10 and elite >= 5
        update_level = 'Elite'
      end

      if (update_level != 'Recruit')
        membership_level = MembershipLevel.find_by(name: update_level)
        user.membership_level_id = membership_level.id
        user.save
      end
  end

  def set_referral_code
    loop do
      self.referral_code = SecureRandom.hex(6)
      break unless self.class.exists?(referral_code: referral_code)
    end
  end

  def complete_referral!
    return if self.referral_completed_at?

    update(referral_completed_at: Time.zone.now)

    # POINT CREATION
    if self.referred_by_id?
        self.referred_by.add_points(2, category: 'Recruiting')  # Adds 2 recruiting points and 2 redeemable rockets
        self.referred_by.add_points(2, category: 'Total')  # Adds 2 total points and 2 redeemable rockets
        self.referred_by.subtract_points(2)                     # Removes the second 2 redeemable rockets                                            # Result = 2 recruiting points, 2 total points, and 2 rockets
    end
    # BADGE CREATION
    # Add badge creation code here

    # Add additional code here.
    # This additional code is called once the referred user fully completes the signup progress.  When that happens,
    # this code will govern what rewards the current user will receive for completing a referral
    # Example: Add credit to referred_by user
  end

  def mailboxer_email(object)
    nil
  end

  def self.execute_sql(*sql_array)
    connection.execute(send(:sanitize_sql_array, sql_array))
  end

  def stripe_customer
    if self.stripe_id.present?
      Stripe::Customer.retrieve(self.stripe_id)
    else
      stripe_customer = Stripe::Customer.create(email:self.email)
      self.update_attribute(:stripe_id, stripe_customer.id)
      stripe_customer
    end
  end

  def stripe_subscription
    if self.stripe_subscription_id.present?
      Stripe::Subscription.retrieve(self.stripe_subscription_id)
    end
  end

  def subscribed?
    # self.customer.subscriptions.any? {|s|s.plan.id==plan_id}
    stripe_subscription_id? || (subscription_expires_at? && Time.zone.now < subscription_expires_at)
  end

  def plan
    self.stripe_subscription.try(:plan).try(:id)
  end

  def unlimited_dives?
    subscribed? && self.plan == 'unlimited-dives'
  end

  def unlimited_certs?
    subscribed? && self.plan == 'unlimited-certs'
  end

  def all_access?
    subscribed? && self.plan == 'all-access'
  end

  def self.points_x_days_old(num_days)
    includes(sash: [scores: :score_points]).where('merit_score_points.created_at::date >= ?', num_days.days.ago).references(:merit_score_points)
  end

  def self.total_points_within(min_pts, max_pts)

  end

  protected
    def confirmation_required?
      false
    end

end```
bhavyabh commented 5 years ago

Error message: image

redtachyons commented 5 years ago

@bhavyabh

User.find_by('tanvi@gmail.com').subtract_points(10)

where returns active relation object, but subtract point is defined on user object

tute commented 5 years ago

@bhavyabh does @redtachyons comment solve your issue? Do you have other questions? Best!

bhavyabh commented 5 years ago

@redtachyons Thank you very much. It is working with find_by.

@tute Thank you. I do not have other question.

tute commented 5 years ago

Glad it worked!