views:

118

answers:

3

I have a form that is used to record a transaction. Liquid is moved from one tank to another. My form takes the from tank and the to tank and the number of gallons transferred. i would like this to be entered into the database as two rows. The first would be the from Tank ID and a negative number and the second row would be the to Tank ID and a positive number.

Example: Transferring 36 gallons from Tank 1 to Tank 2

    id   | tank_id | tran_amount
   ------------------------------
     1   |    1    |     -36
     2   |    2    |      36

This is something that I would have achieved with ease writing SQL code in PHP but I am at a loss in Rails. How can I do this from one form?

+1  A: 

Something seems missing in your database model here, don't you want something to tie the transfer together? I would do:

id | from_tank_id | to_tank_id | transfer_amount

If you are stuck with the existing model, which assume is in a model called Transfer, there is nothing that prevents you from creating two in the controller, just put them in a transaction.

#in TransferController.create
amount = params[:amount].to_i
Transfer.transaction do
  Transfer.create(:tank_id => params[:from_tank_id], :tran_amount => -amount)
  Transfer.create(:tank_id => params[:to_tank_id], :tran_amount => amount)
end
MattMcKnight
I'm sticking with the original model. Thanks for your help. I am stuck in thinking of SQL transactions instead of ActiveRecord. It's harder to figure out, but once I see it it's much easier.
JetShred
Can I put this in the controller? How do I pull the params from the hash?
JetShred
Edited to show use of params
MattMcKnight
+1  A: 

His model is correct. An accounting-style transaction table only holds the account ID and the transaction amount. You must use a transaction save to ensure that both records save correctly or both records fail.

For this, I'd go for just the easy form tag version.

<% form_tag url => { :controller => "controller", :action => "action" }, :method => "post" do %>
     <p>From Account: <%= text_field_tag :from_account %></p>
     <p>To Account: <%= text_field_tag :to_account %></p>
     <p>Amount: <%= text_field_tag :amount %></p>
     <p><%= submit_tag "Transfer" %>

<% end %>

In the controller, I'd then create both transfer models and save them together as a transaction.

Jarrett Meyer
There is generally a transaction ID that ties both sides of the entry together. That is missing here.
MattMcKnight
I am going to add this since it would make it much easier to delete or edit a transaction down the road.
JetShred
Transactions in RoR: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
Jarrett Meyer
+1  A: 

I would model this differently. Hopefully this gives you some ideas... I'm not sure if it'll work as is...

class TankTransfer < AR:B
    has_one :from_transfer
    has_one :to_transfer

    attr_accessible :from_tank
    attr_accessible :to_tank
    attr_accessible :amount_to_transfer

    before_create :create_transfers
protected
    def create_transfers
      self.to_transfer.build(:tank => self.to_tank, :amount => self.amount_to_transfer)
      self.from_transfer.build(:tank=> self.from_tank, :amount => -self.amount_to_transfer)
    end
end

class Transfer < AR:B
    belongs_to :tank
end

class Tank < AR:B
    has_many :transfers
end

Then you're form would look like (if you were using formtastic):

<% semantic_form_for @tank_transfer do |form| %>
  <% form.inputs :name => "Tank transfer" do %>
    <%= form.input :from_tank %>
    <%= form.input :to_tank %>
    <%= form.input :amount_to_transfer %>
  <% end %>
  <% form.buttons do %>
      <%= form.commit_button %>
  <% end %>
<% end %>

You're controller would be a very simple controller, just like you see in all the examples.

jonnii
+1 for the use of formtastic here - http://github.com/justinfrench/formtastic.
Jarrett Meyer