NeyLive
NeyLive

Reputation: 417

How can I save current user to the database when a purchase is edited?

Question UPDATED: I am trying to save the id of the current user whenever a purchase is edited. Specifically when a purchase is marked as received.

I have a before_update callback to a method that saves the datetime when the purchase is marked as received, that works well, I just need to figure out how to pass the purchase editor's id to the database.

In user.rb

class User < ActiveRecord::Base

  has_many :purchase_edits, :foreign_key => :purchase_editor_id
  has_many :edited_purchases, :through => :purchase_edits
  has_many :created_purchases, :foreign_key => :creator_id, :class_name => "Purchase"
end

In purchase.rb

class Purchase < ActiveRecord::Base
  belongs_to :vendor
  belongs_to :creator, :class_name => "User"
  has_many :purchase_edits, :foreign_key => :edited_purchase_id
  has_many :editors, :through => :purchase_edits, :source => :purchase_editor

  before_update :update_marked_received_date

  ## Saves date when marked received. ##
  def update_marked_received_date
    return unless received == true
    self.marked_received = Time.now
  end
end

In purchase_edit.rb (Join Table)

class PurchaseEdit < ActiveRecord::Base
  belongs_to :purchase_editor, :class_name => "User"
  belongs_to :edited_purchase, :class_name => "Purchase"
end

In purchases_controller.rb, (create & update), I have this:

  def create
    @vendor_options = Vendor.order("name ASC").all.map{ |u| [ u.name, u.id ] }
    @purchase = Purchase.new(purchase_params)
    @purchase.creator = current_user
    if @purchase.save
      redirect_to @purchase
    else
      render 'new'
    end
  end

  def update
    @vendor = Vendor.all
    @vendor_options = Vendor.order("name ASC").all.map{ |u| [ u.name, u.id ] }
    @purchase = Purchase.find(params[:id])
    if @purchase.update(purchase_params)
      flash[:notice] = 'Update successful.'
      redirect_to @purchase
    else
      render 'edit'
    end
  end

In Schema.rb

  create_table "purchases", force: :cascade do |t|
    t.integer  "vendor_id"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "order_number"
    t.string   "tradegecko_url"
    t.integer  "creator_id"
    t.boolean  "received",            default: false, null: false
    t.date     "estimated_ship_date"
    t.boolean  "closed",              default: false, null: false
    t.datetime "marked_received"
  end

  create_table "purchase_edits", id: false, force: :cascade do |t|
    t.integer "purchase_editor_id", null: false
    t.integer "edited_purchase_id", null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "",    null: false
    t.string   "encrypted_password",     default: "",    null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,     null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                             null: false
    t.datetime "updated_at",                             null: false
    t.boolean  "admin",                  default: false
  end

Upvotes: 1

Views: 662

Answers (2)

NeyLive
NeyLive

Reputation: 417

For anyone else who comes across this question, (and my future self), this is how I got it to work:

First, in application_controller.rb:

class ApplicationController < ActionController::Base

  before_action :set_current_user

  def set_current_user
    User.current = current_user
  end
end

Then in user.rb:

class User < ActiveRecord::Base

  has_many :created_purchases, class_name: 'Purchase', foreign_key: 'creator_id'
  has_many :received_purchases, class_name: 'Purchase', foreign_key: 'receiver_id'

  def self.current
    Thread.current[:user]
  end
  def self.current=(user)
    Thread.current[:user] = user
  end

  def purchases
    Purchase.where("creator_id = ? OR receiver_id = ?", self.id, self.id)
  end
end

Finally, in purchase.rb:

class Purchase < ActiveRecord::Base

  belongs_to :creator, class_name: "User", foreign_key: "creator_id"
  belongs_to :receiver, class_name: "User", foreign_key: "receiver_id"

  before_update :update_marked_received

  def update_marked_received
    return unless received == true
    if self.marked_received.blank?
      self.marked_received = Time.now
      self.receiver_id = User.current.id
    end
  end
end

Now, when a purchase is marked as received, the timestamp and user are recorded.

Upvotes: 1

Vaibhav Dhoke
Vaibhav Dhoke

Reputation: 459

Class Purchase
  belongs_to :created_by, class_name: 'User', foreign_key: 'created_by_id'
  has_one :marked
end

Class Marked
  belongs_to :purchase
  belongs_to :user
end

This could work in your favour. Moreover, you could keep the relation has_one or has_many marked, according to your requirement.

I would recommend you to create a different model for this because it will be easier to maintain and the approach you are trying to achieve is violation of single responsibility principle. The model Marked will have a foreign key of two models because it has a relationship belongs_to for both the model. Please have a look of belongs to association.

Upvotes: 0

Related Questions