Passed params drop after failed submit - ruby-on-rails

In my app I pass parameters from one controller to another
Firstly I'm creating Company object and pass its id in parameters in redirecting link
companies_controller:
class CompaniesController < ApplicationController
def new
#company = Company.new
end
def create
#company = current_user.companies.build(company_params)
if #company.save
redirect_to new_constituent_path(:constituent, company_id: #company.id)
else
render 'new'
end
end
private
def company_params
params.require(:company).permit(:name)
end
end
After successfully Company saving I'm redirected to creating a Constituent object. I fill company_id or entrepreneur_id with parameters passed in link http://localhost:3000/constituents/new.constituent?company_id=9 for example
constituents/new:
= simple_form_for #constituent do |f|
= f.input :employees
- if params[:entrepreneur_id]
= f.hidden_field :entrepreneur_id, value: params[:entrepreneur_id]
- elsif params[:company_id]
= f.hidden_field :company_id, value: params[:company_id]
= f.button :submit
constituents_controller:
class ConstituentsController < ApplicationController
def new
#constituent = Constituent.new
end
def create
#constituent = Constituent.create(constituent_params)
if #constituent.save
redirect_to root_url
else
render 'new'
end
end
private
def constituent_params
params.require(:constituent).permit(:employees, :company_id, :entrepreneur_id)
end
end
The problem is parameters I passed in link is dropping after failed attempt to save #constituent and company_id or entrepreneur_id is nil. How can I fix it?

This happens because after you submit your form, there are no params[:company_id] = 9 anymore. After render :new is done, you will have params[:constituent][:company_id] = 9.
So, to solve this problem, you need to send not this get request to new Constituent:
http://localhost:3000/constituents/new?company_id=9
But something like this:
http://localhost:3000/constituents/new?constituent[company_id]=9
Your view will become a little bit more ugly, to avoid error if params[:constituent] not exist:
- if params[:constituent]
- if params[:constituent][:entrepreneur_id]
= f.hidden_field :entrepreneur_id, value: params[:constituent][:entrepreneur_id]
- elsif params[:constituent][:company_id]
= f.hidden_field :company_id, value: params[constituent][:company_id]

Related

simple_form_for how to pass params to controller

I want to pass params from event/id(show page) to my order_controller.
I use simple_form_for to pass event.id and promocode that input by user
#event.show.html.haml
= simple_form_for order_url, url: orders_path(#event, :promocode), method: :post do |f|
= f.hidden_field :event_id, params: {id: #event.id}
= f.input :promocode, value: :promocode, class: 'form-control', placeholder: "Enter your PromoCode"
= f.submit 'APPLY PromoCode'
IDK if a need hidden_field to pass event_id
#order_controller
class OrdersController < ApplicationController
before_action :order, only: %i[show]
def index
#orders = Order.all.order(created_at: :desc).page(params[:page]).per(5)
end
def show; end
def create
#order = Order.create(title: event.title, user_id: current_user.id, event_id: event.id, order_amount: event.price, order_currency: event.currency)
if !promo.nil?
redirect_to_order
elsif #order.save
redirect_to checkout_create_path(id: #order.id)
else
redirect_to event, alert: 'Something went wrong, try again later'
end
end
def redirect_to_order
promo_validate
order_amount_promo_code = #order.order_amount - promo.promo_code_amount
order.update(order_amount: order_amount_promo_code)
redirect_to #order
end
def promo_validate
if promo.present? && promo.promo_code_amount.positive? && promo.promo_code_currency == event.currency
promo.update(order_id: #order.id)
else
redirect_to event, alert: "This PromoCode is invalid or Your PromoCode Currency doesn't match with Event"
end
end
private
def promo
#promo ||= PromoCode.find_by(uuid: params[:promocode])
end
def event
#event ||= Event.find(params[:id])
end
def order
#order ||= Order.find(params[:id])
end
def order_params
params.require(:order).permit(:title, :event_id, :promocode, :event)
end
end
I'm using methods def event and def promo to take this params from view.
Also my routes look like this.
resources :events
resources :orders
I would nest the route:
resources :events do
resources :orders, shallow: true
end
This creates an explicit relationship between the two resources that can be seen by just looking at the URL. To create a order tied to an even you send a POST request to /events/:event_id/orders.
class EventsController
def show
# ..
#order = #event.orders.new
end
end
= simple_form_for [#event, #order] do |f|
= f.input :promocode, value: :promocode, class: 'form-control', placeholder: "Enter your PromoCode"
= f.submit 'APPLY PromoCode'
class OrdersController < ApplicationController
# POST /events/:id/orders
def create
#event = Event.find(params[:event_id])
#order = #event.orders.new(title: #event.title, user: current_user order_amount: #event.price, order_currency: #event.currency)
begin
#promo = PromoCode.find_by!(uuid: params[:order][:promocode])
rescue ActiveRecord::RecordNotFound
#order.errors.add(:promocode, 'is invalid')
end
if #order.save
redirect_to checkout_create_path(id: #order.id)
else
redirect_to #event, alert: 'Something went wrong, try again later'
end
end
# ...
end
Other then that your handling of promo codes is very iffy. Instead of monkying around and deducting the rebate from the "amount" by updating the record you should store both the original sales price and the rebate and then calculate the total at checkout - which should also be stored separately. Not doing so amounts to pretty dismal record keeping and might get you in trouble - when it comes to money always play it safe.

Rails 4 Error: ActiveRecord::RecordNotFound Couldn't find 'id'

I'm fairly new to rails and struggling on changing database values after the user successfully paid via stripe. Additionally after paying, it somehow redirects me everytime to '/subscriberjobs/1' where the following error appears. Instead it should direct to the root_path of the application.
This is the appearing error:
ActiveRecord::RecordNotFound in SubscriberjobsController#update
Couldn't find Job with 'id'=
Here is what I've got:
Routes
resources :subscriberjobs
resources :jobs
Jobs Controller
def new
if current_user
#job = current_user.jobs.build
else
redirect_to new_user_session_path
end
end
def create
#job = current_user.jobs.build(job_params)
if #job.save
redirect_to "/subscriberjobs/new?job_id=#{#job.id}"
else
render 'new'
end
end
Subscriberjobs Controller (Here is what doesn't work!)
class SubscriberjobsController < ApplicationController
before_filter :authenticate_user!
def new
end
def update
#job = Job.find(params[:job_id])
token = params[stripeToken]
customer = Stripe::Customer.create(
card: token,
plan: 1004,
email: current_user.email
)
#job.is_active = true
#job.is_featured = false
#job.stripe_id = customer.id
#job.save
redirect_to root_path
end
end
Form
= simple_form_for #job do |f|
= f.input :company, required: true
= f.input :title, required: true
= f.input :job_filename
= f.input :location, required: true
= f.input :sort
= f.input :tag_list, required: true
= f.input :content_one
= f.input :content_two
= f.input :content_three
= f.hidden_field :job_id, value: params[:id]
= f.button :submit
Please tell me if you need additional information. Every answer is very appreciated. Thanks!
Your problem is here:
#job = Job.find(params[:job_id])
It looks, params[:job_id] is equal nil. Maybe your params job_id is called something different, for example [:id] ?
Other question is, why you updating Job in SubscriberJobsController ? Maybe will be bether if you use JobsController to do this ?
Try params[:job][:id]. Use View Source in the browser or e.g. Chrome dev tools to check how the form is rendered as it will tell you the parameters are being set. Also, watch the Rails log when you submit the form - you'll see what parameters are submitted.

Ruby on rails. Passing params from view to controller

I'm having what I assume must be a simple problem but I just can't figure it out. I'm trying to update an attribute in one model when another is created.
In my view:
<%= link_to 'Click here to rate this user', new_user_review_path(:user_id => request.user.id, :gigid => request.gig.id), remote: true %>
Which passes params :gigid and :user_id
Than my controller:
def new
#review = Review.new
#gig = Gig.find(params[:gigid])
end
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
respond_to do |format|
format.html {redirect_to session.delete(:return_to), flash[:notice] = "Thankyou for your rating!"}
format.js
end
else
render 'new'
end
end
But I get undefined method 'update'for nil:NilCLass:
I know the params are passing and the 'Gig' can be updated as :
def new
#review = Review.new
Gig.find(params[:gigid]).update(reviewed: true)
end
updates the attribute fine, but when I click 'New review' not when the review is actually created.
Adding :
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
Gig.find(params[:gigid]).update(reviewed: true)
etc etc etc
gives me the same undefined method 'update'for nil:NilCLass:
I have tried with find_by_id instead of find which makes no difference.
EDIT:
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
etc etc etc
Doesn't work either. I get no errors, but the gig ID is still 'nil'.
The params are passing to the 'New' action but not the 'Create' action. I feel this should be very easy but I'm just not seeing it at the moment.
But I get undefined method 'update'for nil:NilCLass:
The error is that you have not defined #gig in your create action.
Since Rails is built on HTTP, and HTTP is stateless, you have to set the "instance" variables with each new request:
def new
#review = Review.new
#gig = Gig.find params[:gigid]
end
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
A much better pattern for you would be to use the after_create callback in your Review model:
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :gig #-> I presume
after_create :set_gig
private
def set_gig
self.gig.update(reviewed: true)
end
end
--
If you wanted to make the Gig update within your current setup, you'll be best sending the gig_id param through the request (not the link):
#app/views/reviews/new.html.erb
<%= form_for [#user, #review] do |f| %>
<%= f.hidden_field :gig_id, #gig.id %> #-> params[:reviews][:gig_id]
...
<% end %>
This will make params[:review][:gig_id] available in the create action, with which you'll be able to use in your code.
The problem is, you never assigned a value to #gig in your create method. I can't see your form, but you need something like this in your create method:
#gig = Gig.find params[:gigid]
Assuming that you're passing the parameter :gigid to #create
In the second example you showed, I'm not sure what's going on, but you should be getting a ActiveRecord::RecordNotFound exception on the find().
Try the below code for update operation.
gig_record = Gig.find_by_id(params[:gigid])
gig_record.update_attribute(reviewed: true) unless gig_record.blank?

Rails, send params to controller action through link_to

Is it safe/acceptable to send params this way to create action in the controller? Is there any potential problems?
<%= link_to "Acceptance", acceptances_path(acceptance: {favor_id: #favor.id, user_id: current_user.id}), method: :post %>
and then in controller
class AcceptancesController < ApplicationController
def create
#acceptance = Acceptance.new(acceptance_params)
if #acceptance.save
redirect_to favors_path
else
render :template => 'favors/index'
end
end
private
def acceptance_params
params.require(:acceptance).permit(:favor_id, :user_id)
end
end
Thanks for your time in advance!
The best (and the safest) you could do is assigning these id's in controller.
Since you have access to #favor and current_user objects, you'd be better of doing this:
def create
#acceptance = Acceptance.new(acceptance_params)
#acceptance.favor_id = #favor.id
#acceptance.user_id = current_user.id
# code omitted
end

Update attributes separately in Rails

Trying to update 2 attributes to a User model, this is my current code in the Users controller:
def update
#user = User.find(params[:id])
if #user.update_attributes(songkickID: params[:user][:songkickID], jamID: params[:user][:jamID])
redirect_to #user
else
redirect_to #user
end
end
The Songkick ID and the Jam ID are entered into 2 different fields. However, with the current code, if I attempt to update the Jam ID on its own, it updates that attribute, but then redirects to the user page (as expected), where the Songkick ID is now nil. Upon entering the Songkick ID again, the Jam ID becomes nil. I suppose this is because they are both part of the same if statement in the controller?
I attempted to use an elsif for the jamID params, but it does not seem to recognise at all (i.e. won't update that attribute for the user). Also attempted || conditional operator.
EDIT: Here's the 2 different forms:
<%= form_for(#user) do |f| %>
<%= f.text_field :jamID, :id=>"jamURL" %>
<%= f.submit "Jam ID", :onclick => "changeImg()", id: "saveJam" %>
<% end %>
and
<%= form_for(#user) do |f| %>
<%= f.text_field :songkickID %>
<%= f.submit "Songkick ID", :type => :image, :src => image_path("songkicklogo.png"), id: "skLogo" %>
<% end %>
And I tried modifiying the code to update_column, but I get wrong number of arguments (1 for 2).
EDIT 2: Following layout from Hartl's Rails Tutorial, I attempted this to define strong parameters:
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
But I still get the Forbidden Attributes Error?
EDIT 3: The following code passes, but I worry it doesn't adhere to Rails 4 strong parameters:
Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
end
If I move update to below the update method, I get an undefined variable/method error for user_params, and I cannot make it private.
So - why are you explicitly naming the attributes in your update_attributes?
You should be able to use the following:
#user.update_attributes(params[:user])
Remember that if you've named your form fields correctly, params[:user] is a hash that will already have the keys you want (:songkickID etc)
Now - you will get one of two things coming through to your action, which you then pass through to update_attributes as:
{:songkickID => someID}
{:jamID => someOtherID}
which will correctly update your user and only change the one that is passed.
The problem with your earlier code was that what you passed to update attribute was:
{:songkickID => someID, :jamID => nil}
{:songkickID => nil, :jamID => someOtherID}
which was deliberately overwriting the other id with the nil you passed.
EDIT from OP: Thanks for this, and here's my final controller code:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
end
In last case scenario:
def update
if params[:user][:songkickID]
received_param = { songkickID: params[:user][:songkickID] }
elsif params[:user][:jamID]
received_param = { jamID: params[:user][:jamID] }
end
#user.update_attributes(received_param)
redirect_to #user
end
Note: I removed the last condition since it wasn't useful

Resources