I am trying to prevent my application to show error "Couldn't find ReceiptVoucher with id=53". Actually what i am doing i am opening two windows on first one i am listing all the record and on second window i am accessing particular record suppose record with id 53. Now i have deleted that record from index page and again trying to delete it from second window which was opened earlier.
Here is my controller delete action:
def destroy
#receipt_voucher = ReceiptVoucher.find(params[:id])
if #receipt_voucher.blank?
redirect_to(receipt_vouchers_url, :notice => "record not found")
else
#receipt_voucher.destroy
respond_to do |format|
#receipt_voucher.register_user_action(request.remote_ip, 'deleted')
format.html { redirect_to(receipt_vouchers_url, :notice => "receipt voucher has been successfully deleted") }
end
end
end
How to handle this in controller. Any help would be thankful
Try this instead: #receipt_voucher = ReceiptVoucher.where(id: params[:id]).first
Related
I just updated my Rails 6 app to Rails 7 and have problems updating my :patch and :delete links to Turbo.
For example, in one of my views I have this link...
link_to("Mark as sent", status_url(quote), :data => {:'turbo_method' => :patch})
... which is handled by this controller:
class StatusController < ApplicationController
def update
#quote = Quote.find(params[:id])
#quote.send_it! # Should trigger AASM
flash[:notice] = "Quote marked as sent."
redirect_to edit_quote_path(#quote)
end
end
In the model I am using AASM as a state machine:
class Quote < ApplicationRecord
include AASM
aasm :column => "status" do
state :draft, :initial => true
state :inquired
state :sent
state :downloaded
state :accepted
state :rejected
event :send_it do
transitions :from => [:draft, :inquired], :to => :sent
end
...
event :reset_it do
transitions :from => [:inquired, :sent, :downloaded, :accepted, :rejected], :to => :draft
end
end
end
The problem is that the state machine does not get triggered when I hit the link. The flash message and the redirect work but the state is not changed in the database. When I replace #quote.send_it! with #quote.update_column(:status, "sent")it works, however.
Can anybody tell me what I'm missing here?
I don't quite see how turbo is related. Except that I think your redirect isn't actually working:
Redirected to http://127.0.0.1:3000/quotes/1/edit
Completed 302 Found in 18ms (ActiveRecord: 4.3ms | Allocations: 7265)
Started PATCH "/quotes/1/edit" for 127.0.0.1 at 2022-08-12
ActionController::RoutingError (No route matches [PATCH] "/quotes/1/edit"):
# NOTE: ^ not quite a redirect
# v but it doesn't show on a page, it just refreshes the current one.
Started GET "/quotes" for 127.0.0.1 at 2022-08-12 17:51:28 -0400
# and if the current page were /quotes/1/edit then it would look like
# redirect worked, but I was submitting from /quotes.
Update your controller to actually show any errors:
def update
#quote = Quote.find(params[:id])
# NOTE: if transition fails, `send_it!` returns `false`
# (or raises an error for invalid transitions)
# when you run `#quote.update_column(:status, "sent")`
# validations and state machine are not triggered and it works.
if #quote.send_it!
flash.notice = "Quote marked as sent."
else
flash.notice = #quote.errors.full_messages.join(", ")
end
respond_to do |format|
# in case you want add a stream response later
# format.turbo_stream { # TODO }
format.html { redirect_to edit_quote_path(#quote), status: :see_other }
# NOTE: Redirect as a GET request instead of PATCH ^
end
end
Or just add whiny_persistence flag and check the logs, this will raise validation errors:
aasm column: :status, whiny_persistence: true do
Not sure where you got the mark_as_ from, change that to #quote.aasm.fire! status.
Edit
Sorry, not status, needs to be the event, just use the right event.
In my Rails 6 app I have a very simple controller that displays download links to a user's Stripe invoice PDFs:
class ReceiptsController < ApplicationController
before_action :signed_in_user
def index
receipts = current_account.receipts
end
def show
receipt = current_account.receipts.find(params[:id])
stripe_invoice = Stripe::Invoice.retrieve(receipt.stripe_invoice_id)
redirect_to stripe_invoice.invoice_pdf
end
end
Since Stripe doesn't provide permanent invoice URLs (please correct me if I am wrong), I am storing each invoice's Stripe ID in the database and then use that ID to lookup the current URL to the invoice PDF from the Stripe API.
The problem is that this works most of the time but not all the time. The spec that I created for the controller show action fails in about 20 % of cases because the two URLs do not match:
describe ReceiptsController, :type => :controller do
before :each do
#account = FactoryBot.create(:activated_account)
#user = #account.users.create(FactoryBot.attributes_for(:user))
sign_in(#user)
end
describe 'GET #show' do
# The implementation details of this block don't really matter
before :each do
Customers::FindOrCreate.call(#account)
stripe_subscription = Subscriptions::CreateRemote.call(#account,:payment_behavior => "default_incomplete")
#stripe_invoice = stripe_subscription.latest_invoice
#receipt = Receipts::Create.call(#stripe_invoice)
end
# This test fails in about 20 % of cases because the redirect does not go to #stripe_invoice.invoice_pdf but a slightly different URL
it "redirects to Stripe invoice PDF" do
get :show, :params => {:id => #receipt}
expect(response).to redirect_to #stripe_invoice.invoice_pdf
end
end
end
How can this be? Does the invoice_pdf property of a Stripe invoice change every few seconds? I've been trying to work this out for days now but can't get my head around it.
Addition:
This is a typical test failure that I get quite often:
Expected response to be a redirect to <https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY30200oOxX3A1/pdf?s=ap> but was a redirect to <https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY402001iYCSUbn/pdf?s=ap>.
Expected "https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY30200oOxX3A1F/pdf?s=ap" to be === "https://pay.stripe.com/invoice/acct_105jfm2HzYSlmhv7/test_YWNjdF8xMDJqc20yS3pZUmxzaHc0LF9NMGZONnFzNUpPTjlObVprd0hvdGpIdWFUamJHTTVxLDQ3Njc3MDY402001iYCSUbn/pdf?s=ap".
I am trying to redirect the canceled page to the previous one when the item's been canceled but at the moment the codes below don't work - can you help?
def destroy
order.cancel
respond_to do |format|
format.html { redirect_to request.referer.include? "cancel" ? request.referer : order_path(order.shopify_id), notice: 'Order cancelled successfully!' }
end
end
def cancel
shopify_order.cancel
fulfilment_orders.each do |fo|
fo.update!(state: :cancelled) unless fo.state.in?(%i[shipped delivered could_not_deliver])
end
end
You should carefully check the operator precedence as well as warnings you get while Ruby is executing your code.
Consider this snippet.
"cancel_foo_bar".include? "cancel" ? "foo" : "bar"
(pry):1: warning: string literal in condition
#⇒ true
It returns true because it’s actually equivalent to:
"cancel_foo_bar".include?("cancel" ? "foo" : "bar")
The same in your condition, include? receives the result of ternary operator execution, not "cancel" string. This probably would work:
format.html do
redirect_url =
if request.referer.include?("cancel")
request.referer
else
order_path(order.shopify_id)
end
redirect_to(redirect_url,
notice: 'Order cancelled successfully!')
end
I have a method with an if statement that i want to get onto one line if possible. However one part of the condition has two results - pay later and a redirect_to. Is is possible to have this on one line?
It doesnt like the syntax when i do it. (I know this will be very long if on one line)
def invoice
if #invoice.reason?
pay_later
redirect_to admin_invoices_path, notice: t(".success_delay")
else
redirect_to new_admin_invoice_payment_path(#invoice)
end
end
Sure, you ca try
def invoice
#invoice.reason? ? pay_later && redirect_to(admin_invoices_path, notice: t(".success_delay")) : redirect_to(new_admin_invoice_payment_path(#invoice))
end
But it's not cool at all. And it works only if pay_later does not return a falsey value
Yes but you probably don't want to.
def invoice
(pay_later; return redirect_to admin_invoices_path, notice: t(".success_delay")) if #invoice.reason?
redirect_to new_admin_invoice_payment_path(#invoice)
end
A common way to avoid placing your whole method body inside an if..else block is to use a guard clause:
def invoice
return redirect_to new_admin_invoice_payment_path(#invoice) unless #invoice.reason?
pay_later
redirect_to admin_invoices_path, notice: t(".success_delay")
end
I have a Rails 3.2 application hosted on Heroku, and after local development of a new blog resource it for some reason is running into issues when on my Heroku staging application by throwing an error that says
Started GET "/blog_posts" for 24.16.156.31 at 2014-09-16 01:27:59 +0000
Rendered blog_posts/index.html.haml within layouts/application (25.9ms)
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"blog_posts", :id=>nil}):
app/views/blog_posts/index.html.haml:89:in `_app_views_blog_posts_index_html_haml___3120682798112947929_70212833553560'
app/controllers/blog_posts_controller.rb:10:in `index'
Yet when I run
heroku run rake routes
to display all available routes I can clearly see
blog_posts GET /blog_posts(.:format) blog_posts#index
POST /blog_posts(.:format) blog_posts#create
new_blog_post GET /blog_posts/new(.:format) blog_posts#new
edit_blog_post GET /blog_posts/:id/edit(.:format) blog_posts#edit
blog_post GET /blog_posts/:id(.:format) blog_posts#show
PUT /blog_posts/:id(.:format) blog_posts#update
DELETE /blog_posts/:id(.:format) blog_posts#destroy
at the top of my routes.rb file I have
resources :blog_posts
The only thing I could think of was that when I inherited this project and went ahead to generate the scaffolding for a blog, it created the blog_post_controller of type
class BlogPostsController < InheritedResources::Base
instead of the normal
class BlogPostsController < ApplicationController
which has all the explicitly defined show, index, new, edit, etc, actions that you can alter.
So to cause the scaffolding to return to ApplicationController I added to application.rb this line
config.app_generators.scaffold_controller = :scaffold_controller
Any ideas?
Edit:
blog_posts_controller.rb show and index actions
def index
#blog_posts = BlogPost.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #blog_posts }
end
end
# GET /blog_posts/1
# GET /blog_posts/1.json
def show
#blog_post = BlogPost.find(params[:id])
hash = session.exists?
respond_to do |format|
format.html # show.html.erb
format.json { render json: #blog_post }
end
end
Additionally, the URL being accessed is
http://app.herokuapp.com/blog_posts
which should be triggering the index action, not show.
When I attempt to hit blog_posts/1 where 1 is a valid blog_post id, I get
Parameters: {"id"=>"1"}
Rendered blog_posts/show.html.haml within layouts/application (31.9ms)
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"blog_posts", :id=>nil}):
routes.rb
resources :blog_posts
You try to build an url with a BlogPost that does not exist. Did you double check that a BlogPost with the id 1 exists in your production database? Did you load the record that you pass to your url helper or did you hard code that id?