I have an object(Transaction) that belongs_to User and User has_many transactions. When I try and create this object in my rails form I get the following error:
undefined method `transaction_kind' for nil:NilClass
app/models/transaction.rb:10:in `create_transaction'
app/controllers/transactions_controller.rb:17:in `create'
The params hash being passed through my console after I submit the form looks like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXXXX", "transaction"=>{"transaction_kind"=>"Deposit", "user_id"=>"113", "credit"=>"99"}, "commit"=>"Submit Request", "lender_id"=>"113"}
Transaction.rb looks like this:
class Transaction < ActiveRecord::Base
belongs_to :user
after_save :create_transaction
attr_accessible :transaction_kind, :user_id, :credit, :debit, :created_at
def create_transaction
client = Restforce.new
credit = '012c00000004k5A'
debit = '012c00000004k55'
if #transaction.transaction_kind == "Deposit"
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: credit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Deposit', Transaction_Type__c: self.transaction_kind)
else
client.create!('Transaction__c', Account__c: self.salesforce_id, RecordTypeId: debit, Debit_Amount__c: self.debit, Credit_Amount__c: self.credit, Recorded_On__c: self.created_at, Status__c: 'New Transaction', Type: 'Withdrawal', Transaction_Type__c: self.transaction_kind)
end
end
end
new.html.erb has the following form code:
<%= form_for [#user, #transaction], url: lender_transaction_path(#user) do |f| %>
<%= f.hidden_field :transaction_kind, :value => "Deposit" %>
<%= f.hidden_field :user_id, :value => #user.id %>
<%= f.label :credit, :class => "required" %>
<%= f.text_field :credit, :autofocus => :true, :class => "form-control margin-bottom-20 required"%>
<%= f.submit 'Submit Request', :class => "btn-u btn-u-primary" %>
<% end %>
transactions_controller.rb
class TransactionsController < ApplicationController
before_filter :authenticate_user!
def new
#user = current_user
#transaction = Transaction.new
if #user.activated?
client = Restforce.new
#account = client.find('Account', #user.salesforce_id, 'Account_Id')
transaction_query = "select from where Account__c ='%s' AND " % #account.Id.to_s
#transactions = client.query(transaction_query)
end
end
def create
#user = current_user
#transaction = Transaction.create(transaction_params)
if #transaction.save
redirect_to new_lender_transaction_path(#user)
end
end
private
def transaction_params
params.require(:transaction).permit(:transaction_kind, :credit, :debit, :created_at)
end
end
Any help with this issue would be great. Or any ideas on how to debug this further. Thanks!
You can't pass an instance variable from controller to model, so the Transaction model doesn't know what #transaction is and thus supposes it is as a nil
I would change the code into this:
if self.transaction_kind == "Deposit"
The self will make it work. If it is not, try using attr_accessor :transaction_kind or simply put if transaction_kind == "Deposit"
Also, I believe it would be better if you refactor the client.create! into:
Restforce.create!(...)
which will save you from writing another client = Restforce.new line.
Related
I'm creating a join model Invite for has_many through relationship with Party and Guest but I get empty params[:party_id]. The user is logged in as a guest and the guest can see all the party list, and the guest can click individual party and there is a link to join the party. Once the guest click the "Join this party", it goes to '/parties/2/invites/new' and I have a form for the guest to fill out. I get stuck when the guest submit the form. The url changed to '/parties/2/invites' but I still see the form view and once I refresh the page, it shows the invites index page.
I put binding.pry in the invites#create and type params, I can see the party_is "". and I see "commit"=>"Join!", "controller"=>"invites", "action"=>"create", "party_id"=>"3"} permitted: false>.
def new
#invite = Invite.new
#party_id = params[:party_id]
end
def create
#invite = Invite.new(invite_params)
binding.pry
if #invite.save
redirect_to guest_invites_path(current_user)
else
#party = Party.find(params[:party_id])
render :new
end
end
private
def invite_params
params.require(:invite).permit(:add_on, :rsvp, :guest, :party_id)
end
<%= form_with model: #invite, url: [#party, #invite], local: true do |f| %>
<%= f.label :add_on, "Add On" %>
<%= f.select :add_on, [1, 2, 3, 4], :prompt => 'Select One' %><br>
<%= f.label :rsvp, "RSVP" %>
<%= f.select :rsvp, [['Yes', true], ['No', false]], :include_blank => true %>
<%= f.hidden_field :party_id, :value => #party_id %>
<%= f.submit "Join!" %>
<% end %>
class Invite < ApplicationRecord
belongs_to :party
belongs_to :guest
validates :add_on, :rsvp, presence: true
accepts_nested_attributes_for :guest, :party
end
[4] pry(#)> raise params.inspect
RuntimeError: "68nwEzR31GS2mcJGq9WhUrP0sp9zSjZENqY4/iosH8sn0zHRxz+PRXXWsQVJDG100FTc+dG4epdA/Cr1DsiRbQ==", "invite"=>"1", "rsvp"=>"true", "party_id"=>""} permitted: false>, "commit"=>"Join!", "controller"=>"invites", "action"=>"create", "party_id"=>"3"} permitted: false>
from (pry):4:in `create'
Make some changes to your code
From your form, remove this line
<%= f.hidden_field :party_id, :value => #party_id %>
and then in your controller rewrite your create method to this
def create
#party = Party.find(params[:party_id])
#invite = Invite.new(invite_params)
#invite.party_id = #party.id
if #invite.save
redirect_to guest_invites_path(current_user)
else
render :new
end
end
So, since your URL already has party_id, you don't need to enter it in your form. Try this and let me know!
Upon clicking submit only the Duel attributes are passing - not Dueler.
duels_controller.rb
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy]) # This pulls in the ID for Challenged User
# Current User
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
# Challenged User
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
I think I have to submerge the dueler info (i.e. full_name and collection_select) within something like <%= simple_form_for(#dueler) do |f| %>, but then I don't want two separate submit buttons. When the user clicks submit the dueler and duel information should both submit since they go hand-in-hand. Right now only the duel information submits and the duelers are never created.
duels/_form.html.erb
<%= simple_form_for(#duel) do |f| %>
<%= current_user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #current_user_challenges, :id, :full_challenge, include_blank: true) %>
<%= #user.full_name %> WILL <%= collection_select(:dueler, :challenge_id, #challenged_user_challenges, :id, :full_challenge, include_blank: true) %>
THE LOSER WILL <%= f.text_field :consequence %>.
<%= f.submit %>
<% end %>
UPDATE
Originally I had this in the _form:
<%= f.fields_for :duelers do |dueler| %>
<%= render 'dueler_fields', :f => dueler %>
<% end %>
But I took it out because the duels_controller new logic wasn't passing into it so I moved the code directly into the _form, but now I'm not sure what should take the place of <%= f.fields_for :duelers do |dueler| %>
class Dueler < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
belongs_to :duel
end
class Duel < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
has_many :duelers
accepts_nested_attributes_for :duelers, :reject_if => :all_blank, :allow_destroy => true #correct
end
class DuelsController < ApplicationController
before_action :set_duel, only: [:show, :edit, :update, :destroy, :duel_request]
respond_to :html
def index
#duels = Duel.joins(:duelers).all
redirect_to duel(#duel)
end
def duel_request
#dueler = #duel.duelers.where(user_id: current_user)
end
def show
#dueler = Dueler.find_by(user_id: current_user.id)
respond_with(#duel)
end
def user_challenges
#user = User.find_by_name(params[:name])
#challenges = #user.challenges.order(:created_at)
end
def new
#duel = Duel.new
#user = User.find(params[:challenge_daddy])
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
#current_user_challenges = current_user.challenges.order(:created_at)
#duel.duelers << Dueler.new(user_id: #user.id, user_name: #user.name, user_last_name: #user.last_name)
#challenged_user_challenges = #user.challenges.order(:created_at)
respond_with(#duel)
end
def edit
end
def create
#duel = Duel.new(duel_params)
#duel.save
#redirect_to duel_request_url(#duel)
respond_with(#duel)
end
def update
#duel.update(duel_params[:duelers_attributes])
respond_with(#duel)
end
def destroy
#duel.destroy
respond_with(#duel)
end
private
def set_duel
#duel = Duel.find(params[:id])
end
def duel_params
params.require(:duel).permit(:consequence, :reward, duelers_attributes: [:id, :user_id, :challenge_id, :accept])
end
end
If you are using has_many and belongs_to with accepts_nested_attributes you will need to use inverse_of to prevent Rails from attempting to lookup records (which of course don't exist because you haven't yet created them)
Change your Duel model has_many declaration to:
has_many :duelers, inverse_of: :duel
For further details on this and an example of a nested form with has_many relationship using Simple Forms check out:
https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through
Hoping someone can help out with this. I have two models order and date_order. Each order can have multiple date_orders, and I should be able to create many date_orders as I create an order.
How do I do that? As you can see, my code is working well for creating ONE date_order and relating it to the created order.
UPDATE: I have tried to create many "builders" in my orders/new file. It worked on the view, and created an order when I entered multiple dates and times. But the fields_for did not create any date_orders.
orders_controller.rb
def new
#order = Order.new
#order.date_orders.build
end
def create
#order = Order.new(order_params)
if #order.save
flash[:success] = "blah"
redirect_to #order
else
render 'new'
end
end
private
def order_params
params.require(:order).permit(:user_id, :purpose,
date_orders_attributes: [:id, :order_date, :time_start, :time_end, :order_id])
end
order.rb
class Order < ActiveRecord::Base
has_many :date_orders, :dependent => :destroy
accepts_nested_attributes_for :date_orders, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
date_order.rb
class DateOrder < ActiveRecord::Base
belongs_to :order
end
order/new.html.erb
<%= form_for(#order, :html => {:multipart => true}) do |f| %>
## SOME QUESTIONS ##
<%= f.fields_for :date_orders do |builder| %>
<%= builder.label :date %>
<%= builder.date_field :order_date %>
<%= builder.label :starting_time %>
<%= builder.time_field :time_start %>
<%= builder.label :ending_time %>
<%= builder.time_field :time_end %>
<% end %>
<% end %>
Build more orders_dates:
class OrdersController < ApplicationController
def new
#order = Order.new
5.times { #order.date_orders.build } # < === HERE ===
end
private
def order_params
params.require(:order).permit(:user_id, :purpose,
# |- === HERE ===
date_orders_attributes: [:id, :content, :order_date, :time_start, :time_end, :order_id])
end
end
Update:
Also, add content to your strong params whitelist.
I have Users who bet on matches. A single bet is called "Tipp" and the users predict the match score in "tipp.tipp1" and "tipp.tipp2"
I have problems with my form which is supposed to save "tipps" of users.
With the code below I get "Can't mass-assign protected attributes: tipp" although i have set "accepts_nested_attributes_for :tipps" and "attr_accessible :tipps_attributes".
I hope I have provided all the necessary code. Thanks in advance for your help!
Here is the parameters output:
Parameters:
{
"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"mPPpCHjA3f/M2l1Bd3ffO1QUr+kdETGkNE/0CNhbJXE=",
"user" =>{
"tipp"=>{
"6"=>{"tipp1"=>"4","tipp2"=>"6"},
"7"=>{"tipp1"=>"-1","tipp2"=>"-1"},
"8"=>{"tipp1"=>"-1","tipp2"=>"-1"}
}
},
"commit"=>"Update User",
"user_id"=>"1"
}
Shortened Code:
Controllers:
1) Users
class UsersController < ApplicationController
def edit_tipps
#user = current_user
end
def update_tipps
#user = current_user
if #user.update_attributes(params[:user])
flash[:notice] = "success (maybe)"
redirect_to user_edit_tipps_path(#user)
else
flash[:error] = "errors"
redirect_to user_edit_tipps_path(#user)
end
end
Models:
1) Users
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :tipps_attributes
has_many :tipps
accepts_nested_attributes_for :tipps
end
2) Tipps
class Tipp < ActiveRecord::Base
attr_accessible :match_id, :points, :round_id, :tipp1, :tipp2, :user_id
belongs_to :user
end
My Form:
<%= form_for #user, :url => { :action => "update_tipps" } do |user_form| %>
<% #user.tipps.each do |tipp| %>
<%= user_form.fields_for tipp, :index => tipp.id do |tipp_form|%>
<%= tipp_form.text_field :tipp1 %><br/>
<%= tipp_form.text_field :tipp2 %><br/>
<% end %>
<% end %>
<%= submit_or_cancel(user_form) %>
<% end %>
Instead of doing what you did,
you could try either:
1.
Instead of:
<% #user.tipps.each do |tipp| %>
<%= user_form.fields_for tipp, :index => tipp.id do |tipp_form|%>
I would do this:
<%= user_form.fields_for :tipps do |tipp_form| %>
Or:
2.
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :tipps_attributes, :tipps
Goodluck
for now i've got followings:
model => User (name, email)
has_and_belongs_to_many :trips
model => Trip (dest1, dest2)
has_and_belongs_to_many :users
validates :dest1, :dest2, :presence => true
model => TripsUsers (user_id, trip_id) (id => false)
belongs_to :user
belongs_to :trip
As you see from the code, trip model has validation on dest1, and dest2, but it's not showing up an errors. Controller and view defined as follow:
trips_controller.rb
def new
#user = User.find(params[:user_id])
#trip = #user.trips.build
end
def create
#user = User.find(params[:user_id])
#trip = Trip.new(params[:trip])
if #trip.save
#trip.users << #user
redirect_to user_trips_path, notice: "Success"
else
render :new
end
end
_form.html.erb
<%= simple_form_for [#user, #trip] do |f| %>
<%= f.error_notification %>
<%= f.input :dest1 %>
<%= f.input :dest2 %>
<%= f.submit "Submit" %>
<% end %>
According to the rails guide on presence validation, it can't be used with associated objects. Try to use a custom validation:
validate :destinations_presence
def destinations_presence
if dest1.nil?
errors.add(:dest1, "missing dest1")
elsif dest2.nil?
errors.add(:dest1, "missing dest2")
end
end