Having Separate Update actions for different params in controller? - ruby-on-rails

(post updated down below)
My issue: Is that I need a separate update action for the different params in my controller. I need a general update actions for params (minus params in the separate update actions/methods), an update action for :video, and an update action for :order_status
Question: How can I efficiently accomplish having multiple update actions in my controller?
Here is an idea of what I want, and it doesn't work:
def charge_update
respond_to do |format|
#amount = (#order.order_price).to_i * 100
#amount_seller = (#order.order_price).to_i * 75
if #order.update(order_charge)
if user_signed_in? && user.seller?
charge = Stripe::Charge.create({
:amount => (#order.order_price).to_i * 100,
:description => 'Rails Stripe customer',
:currency => 'usd',
:customer => #order.stripe_customer_token,
:destination => {
:amount => #amount_seller ,
:account => (#order.seller.stripe_token),
}
})
#order.order_status = "charged"
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully uploaded.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
end
def cancel_update
respond_to do |format|
if #order.cancel_update(order_update)
if user_signed_in?
if #order.order_status = "cancelled"
format.html { redirect_to #order, notice: 'Order was successfully cancelled.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
end
end
def update
respond_to do |format|
if #order.update( order_params.except(:order_status) )
if user_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
if buyer_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
end
private
def order_params
params.require(:order).permit(:name, :email, :image,:description)
end
def order_status
params.require(:order).permit(:order_status)
end
def order_charge
params.require(:order).permit(:video)
end
...
My issues with what I need to accomplish:
I want a separate action for when an order_status is changed, for each value. Most importantly, I want a certain message to be displayed depending on the value that the order_status column is changed to.
Most important issue:
I need a separate update action for charging customers. This is most important because i can't just have a customer being charged when someone updates a name, or when a seller updates an order_status, etc.
I'm doing something wrong or i need to set up the routes to have the ability to allow multiple update actions?
So how i can separate the updates and params?
UPDATE
I embedded the update methods into the one original method like so...
but i have one issue now, the message notices don't appear correct to the update param. The "Order was successfully updated" appears, which isn't the customized one for when i upload a video or change the ordeR_status column
def update
respond_to do |format|
if params["order_status"]
if user_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully order_status.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
if params["video"]
#amount = (#order.order_price).to_i * 100
#amount_seller = (#order.order_price).to_i * 75
if #order.update(order_charge)
if user_signed_in? && user.seller?
charge = Stripe::Charge.create({
:amount => (#order.order_price).to_i * 100,
:description => 'Rails Stripe customer',
:currency => 'usd',
:customer => #order.stripe_customer_token,
:destination => {
:amount => #amount_seller ,
:account => (#order.seller.stripe_token),
}
})
#order.order_status = "charged"
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully uploaded.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
if #order.update(order_params)
if user_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
if buyer_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
end
So I have two issues now:
The customized messages don't show
and under the :video param update, I want the order status to change the "charged", but what i currently have doesn't do it
Anyone have any ideas on how to improve this?

This seems to have solved it so far. :::
def update
respond_to do |format|
if #order.update(order_status)
if user_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully order_status.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
if #order.update(order_charge)
#amount = (#order.order_price).to_i * 100
#amount_seller = (#order.order_price).to_i * 75
if #order.update(order_charge)
if current_user.seller?
charge = Stripe::Charge.create({
:amount => (#order.order_price).to_i * 100,
:description => 'Rails Stripe customer',
:currency => 'usd',
:customer => #order.stripe_customer_token,
:destination => {
:amount => #amount_seller ,
:account => (#order.seller.stripe_token),
}
})
#order.order_status = "charged"
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully uploaded.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
if #order.update(order_params)
if user_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
if buyer_signed_in?
format.html { redirect_to ([#user, #order]), notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: #order }
else
format.html { render :edit }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
end
private
def order_params
params.require(:order).permit(:name, :email, :image, :video, :description)
end
def order_status
params.require(:order).permit(:order_status)
end
def order_charge
params.require(:order).permit(:video)
end
end
If anyone sees this and thinks they have a better way, please let me know. I'm not sure how convenient or efficient this may be, (embedding all into one method, etc.) but it seems to work. My only issue is that
When i change order_status to cancel, no message appears but it works.
when i change fill in the video param, the order_status message appears. Which i understand but i don't understand why it won't appear when i change the status to cancel - and btw, cancel is a enum of "2".

Related

Rails 7: How to check from outside transaction block if record was updated successfully

I've searched through the rails docs but not find any method which can check if record was corectly updated from outside transaction block because I dont want to put respond_to block into my transaction because it is bad practise. Is there any method like persisted? which I use with create/save method...
def update
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if #invoice.method `some method to check if invoice was updated`
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
I just edit my code as bellow, capture result of the transaction to variable is_updated. When in transaction error occurred then is_updated would be false and changes are rolled back. If no error occurred is_updated true.
def update
is_updated =
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if is_updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end end
Calling .update on an ActiveRecord object will return true if it was able to store it to db or false if any error occurred.
I'd take advantage of that and store its result on a variable, like the following:
def update
updated = false
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
updated = #invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end

Forwarding post parameters in a redirect_to rails

In my rails app, I want the user to be able to select an option in a 'new' form, but if the option already exists, I want it to update the current option.
I have this so far in my create method:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
redirect_to action: 'update', id: Cost.where(:category => #cost.category, :option => #cost.option).first.id
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
The problem is that it redirects me to, for example cost/9 url, which renders the show page. I want the id to send with the cost_params straight to the update method:
def update
#cost = Cost.find(params[:id])
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
Which should redirect to the index page.
is there any efficient way to do this?
And HTTP redirect always results in a GET request, not a POST request, so redirecting to update doesn't really make a lot of sense. That's not a Rails issue, that's just how HTTP works.
If you want to automatically update the relevant record, you have to do that from within the create action. The straightforward but lazy way would be to copy the code from update and paste it into if branch within create. The more correct way would be to extract the relevant part of update out into a separate, private method, and call that method from both create and update, something like:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
#cost = Cost.where(:category => #cost.category, :option => #cost.option).first
really_update
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
def update
#cost = Cost.find(params[:id])
really_update
end
private def really_update
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end

passing array to f.select ruby on rails

On my rails application in the views/cards/_form i have the code for a f.select field:
<%= f.select :tag_speciality, options_for_select(#subdomain.tag_speciality), {}, {class: 'form-control'} %>
That give me the output:
<select class="form-control" name="card[tag_speciality]" id="card_tag_speciality">
<option value="Professor de Yoga">Professor de Yoga</option>
<option value="Professora de Yoga">Professora de Yoga</option>
<option value="Estúdio de Yoga">Estúdio de Yoga</option>
</select>
In my migration file i have:
add_column :cards, :tag_speciality, :string, array: true
When i go to the form and select any option, for example, "Professor de Yoga", and save, i get the result:
[]
instead of:
["Professor de Yoga"]
This is my controller:
def index
#cards = Card.all
end
def create
#card = #user.cards.new card_params
respond_to do |format|
if #card.save
format.html { redirect_to cards_from_subdomain_path(#subdomain.id), notice: 'Card was successfully created.' }
format.json { render :show, status: :created, location: #card }
else
format.html { render :new }
format.json { render json: #card.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #card.update(card_params)
format.html { redirect_to cards_from_subdomain_path(#subdomain.id), notice: 'Card was successfully updated.' }
format.json { render :show, status: :ok, location: #card }
else
format.html { render :edit }
format.json { render json: #card.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def card_params
params.require(:card).permit(
:name,
:phone,
:email,
:cover,
:is_published,
:subdomain_id,
:domain_id,
:profile_id,
:is_solidarity,
:tag_speciality,
:tag_location,
user_id: []
)
end
end
Is there anything that am i missing?
Thanks
Ditto #EJ2015.
Just add
#card.tag_speciality.push(card_params[:tag_speciality])
#card.save
to your create.
respond_to do |format|
if #card.tag_speciality.push(card_params[:tag_speciality]) && #card.save
format.html { redirect_to cards_from_subdomain_path(#subdomain.id), notice: 'Card was successfully created.' }
format.json { render :show, status: :created, location: #card }
else
format.html { render :new }
format.json { render json: #card.errors, status: :unprocessable_entity }
end
end
Since your tag_speciality is an array column, you need to assign the data using array method in your controller.
#card.tag_speciality.push(card_params[:tag_speciality])
#card.save
Of course you need to modify the assignment of other attributes too. By the way, you can see what went wrong in your server log. In this case you should see that the database rejected commits.

Passing an argument on request.referrer

I'm building a site where a link to fill a new form can be clicked from an Event show page
<%= link_to 'Be a Contestant', new_form_path(:event_id => #event.id)%>
This creates a link like
http://localhost:3000/forms/new?event_id=2
Now if the form is filled with an error, when submitted, it returns an error
Couldn't find Event with 'id'=""
So I decided to use the request.referrer to redirect back to the previous page but it doesn't list the errors as use this method
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to request.referrer }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
I also tried this but to no avail.
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to new_form_path(:event_id => request.referrer.params[:event_id]) }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
What you probably really need to do is to add a hidden field event_id to the form because I'm betting that event_id doesn't get propagated from the #new to the #create action.
See here for more information on hidden_field_tag
You usually just render the edit view when there was an error in create:
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { render :edit, alert: 'Error creating ...' }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end

Controller and view rails

I have a Controller Products:
def update
#product = Product.find(params[:id])
respond_to do |format|
if #product.update_attributes(params[:product])
if #product.brand == nil
format.html { redirect_to :controller => 'compositions', :action => 'edit', :id => #product }
format.json { head :no_content }
else
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { head :no_content }
end
else
format.html { render action: "edit" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
The controller products call Controller Compositions, action edit and params :id => #product:
def edit
#composition = Composition.where("productFather_id=?" , #product)
end
def update
#composition = Composition.where("productFather_id=?" , #product)
respond_to do |format|
if #composition.update_attributes(params[:composition])
format.html { redirect_to "/compositions/new", notice: 'Composition was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #composition.errors, status: :unprocessable_entity }
end
end
I search edit compositions of product in views
PLEASE IDEAS THANKS

Resources