In very short.
When I have a form set as POST, the controller picks up the request, processes it and even starts to render the correct view. But the browser stays on the form page
When I switch the form to GET, it works
(yes, I remembered to change the route from get to post and back)
Here is the log:
Started POST "/sooth/search" for 127.0.0.1 at 2022-07-02 13:43:40
-0700 Processing by SoothController#search as TURBO_STREAM Parameters: {"authenticity_token"=>"[FILTERED]",
"search"=>{"name"=>"search keywords"}, "commit"=>"Save Search"}
Rendering layout layouts/application.html.erb Rendering
sooth/search.html.erb within layouts/application
I am rendering the search html page
The line above is a log message in the search.html.erb page
Rendered sooth/search.html.erb within
layouts/application (Duration: 1.0ms | Allocations: 148) Rendered
layout layouts/application.html.erb (Duration: 6.6ms | Allocations:
2710) Completed 200 OK in 15ms (Views: 11.3ms | ActiveRecord: 0.0ms |
Allocations: 4040)
BUT the search page is not displayed. Browser stays on the search form page.
Any hints deeply appreciated.
(And as you have probably guessed, I am day 1 with rails)
EDIT:
class SoothController < ApplicationController
include SoothHelper
def index
puts "sooth index"
template = get_query_template('sooth_search')
puts(template)
end
def search
form_params = params[:search]
puts 'searching' + form_params[:name].to_s
render "sooth/search"
end
end
ROUTES
Rails.application.routes.draw do
Rails.application.routes.draw do
get "/nlp_data", to: "nlp_data#index"
get "/sooth", to: "sooth#index"
post "/sooth/search", to: "sooth#search"
end
Your problem is you are trying to render the same page instead of redirecting to to the sooth page ,and secondly you cannot acces params directly in a post request, instead you must acces it from a strong param method
class SoothController < ApplicationController
include SoothHelper
def index
puts "sooth index"
template = get_query_template('sooth_search')
puts(template)
end
def search
form_params = sooth_params[:search]
puts 'searching' + form_params[:name].to_s
redirect_to "/sooth"
end
private
def sooth_params
params.require(:sooth).permit(:search)
end
end
Related
So I have a 'ThaaliTakhmeens' controller where some actions have their corresponding turbo_stream templates to lazy load instances from databases using hotwire with pagination (pagy). And in those actions, there's a similar logic that I want to factor out into an after_action callback, (following the DRY principle).
After factoring out the code into an after_action, the instances don't show up on the page in fact the after_action doesn't get executed at all which I verified by giving the debugger in it. I have also provided a before_action to those actions which works perfectly fine.
Here's the code:
after_action :set_pagy_thaalis_total, only: [:complete, :pending, :all]
def complete
#tt = ThaaliTakhmeen.includes(:sabeel).completed_year(#year)
end
def pending
#tt = ThaaliTakhmeen.includes(:sabeel).pending_year(#year)
end
def all
#tt = ThaaliTakhmeen.includes(:sabeel).in_the_year(#year)
end
private
def set_pagy_thaalis_total
#total = #tt.count
#pagy, #thaalis = pagy_countless(#tt, items: 8)
debugger
end
Here's the log on visiting the 'complete' action:
Started GET "/takhmeens/2022/complete" for ::1 at 2023-01-21 10:07:35 +0530
Processing by ThaaliTakhmeensController#complete as HTML
Parameters: {"year"=>"2022"}
Rendering layout layouts/application.html.erb
Rendering thaali_takhmeens/complete.html.erb within layouts/application
Rendered shared/_results.html.erb (Duration: 2.4ms | Allocations: 2088)
Rendered thaali_takhmeens/complete.html.erb within layouts/application (Duration: 3.7ms | Allocations: 2396)
Rendered layout layouts/application.html.erb (Duration: 3.9ms | Allocations: 2477)
Completed 500 Internal Server Error in 6ms (ActiveRecord: 0.0ms | Allocations: 3027)
ActionView::Template::Error (undefined method `any?' for nil:NilClass
'.freeze; if instances.any?
^^^^^):
1: <%= turbo_frame_tag :results, data: { turbo_action: "advance" } do %>
2: <div class="container text-center mt-5">
3: <% if instances.any? %>
4: <%= render partial: "theader" %>
5: <div id=<%="#{id}"%> ></div>
6: <%= turbo_frame_tag :pagination, loading: :lazy, src: path %> %>
app/views/shared/_results.html.erb:3
app/views/shared/_results.html.erb:1
app/views/thaali_takhmeens/complete.html.erb:8
Since the after_action callback doesn't run, the instances (#thaalis) object is not set hence this error shows up, and also debugger didn't get executed either.
Here the complete action has both HTML and turbo_steam templates. And just to be clear that the content loads perfectly fine without the need for an after_action callback but that would be against the DRY principle.
So what would be the workaround for this? Is there another way to refactor the code or should I have to set something explicitly in the callback method to get it executed?
Good question. I actually not use after_action often and had to check. https://guides.rubyonrails.org/action_controller_overview.html#after-filters-and-around-filters What I think happen is that the rendering of the view is part of the action.
In your case this is inferred, you have no respond to block like this:
respond_to do |format|
if #record.update(record_params)
format.html { redirect_to a_record_route }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
But the rendering of the template still happens in the action. Before you set some instance variables useful to the view.
What you can do if you really want to dry up your controller is adding set_pagy_thaalis_total at the end of each of your actions and removing the after_action.
EDIt: Also the fact your view is an html.erb or turbo_stream.erb file doesn't really matter.
I've set up a local Rails app that uses Turbo. I'm trying to shim the Turbo Demo iOS app to display my local Rails app. Has anyone been able to do a similar thing?
I switched Demo.current to use the local address, but all the requests show the "Error loading page" screen, with no useful logs coming out of the Demo app.
The Rails app shows my base route as being attempted, with some form of persistence with retrying a 401 error. I changed the SceneController default URL to load a /networks/all-people, which requires an authorized user (via Devise) to hopefully see how the authentication logic would go. Below is the Rails output when running the Demo app:
Started GET "/networks/all-people" for 127.0.0.1 at 2021-01-21 19:50:26 -0500
Processing by NetworksController#all_people as HTML
Completed 401 Unauthorized in 0ms (Allocations: 256)
Started GET "/users/sign_in" for 127.0.0.1 at 2021-01-21 19:50:26 -0500
Processing by Devise::SessionsController#new as HTML
Rendering layout layouts/application.html.erb
Rendering devise/sessions/new.html.erb within layouts/application
Rendered devise/shared/_links.html.erb (Duration: 0.3ms | Allocations: 218)
Rendered devise/sessions/new.html.erb within layouts/application (Duration: 1.7ms | Allocations: 1056)
Rendered layout layouts/application.html.erb (Duration: 9.4ms | Allocations: 7318)
Completed 200 OK in 10ms (Views: 9.8ms | Allocations: 7945)
Has anyone been able to shim the Demo app into working with a local Rails server? I'm entirely unsure of what's happening wrong here, or whether shimming is even a good idea here.
Turbo is being loaded in, as verified by the following event listener fires when visiting from my browser.
<script>
document.addEventListener("turbo:load", function(e) {
console.log("TURBO LOADED");
});
</script>
There are a few things that are needed to get Devise to work with Turbo.
Add app/controllers/turbo_controller:
# frozen_string_literal: true
class TurboController < ApplicationController
class Responder < ActionController::Responder
def to_turbo_stream
controller.render(options.merge(formats: :html))
rescue ActionView::MissingTemplate => e
raise e if get?
if has_errors? && default_action
render rendering_options.merge(formats: :html, status: :unprocessable_entity)
else
redirect_to navigation_location
end
end
end
self.responder = Responder
respond_to :html, :turbo_stream
end
Add data: { turbo: "false" } to your devise login form:
# app/views/devise/sessions/new.html.erb
<%= form_for(resource, as: resource_name, url: session_path(resource_name), data: { turbo: "false" }) do
Update config/initializers/devise.rb:
class TurboFailureApp < Devise::FailureApp
def skip_format?
%w[html turbo_stream */*].include?(request_format.to_s)
end
end
config.parent_controller = "TurboController"
config.navigational_formats = ["*/*", :html, :turbo_stream]
config.warden do |manager|
manager.failure_app = TurboFailureApp
end
Detailed explanation thanks to GoRails!
I have a form being submitted by the resident of a condominium to apply a pass for a visitor.
Upon submission I have setup the controller to render a template or redirect it to another path depending on the input of the form and display a flash message on the top of the page after clicking the submit button.
Somehow redirect works fine but render does nothing to the page.
Did try flash.now with render but no flash and it looks like it is not loading anything new on the page.
class VisitorPassesController < ApplicationController
def new
#visitor_pass = VisitorPass.new
#controller = "visitor_passes"
end
def create
unless resident && correct_resident_key?
flash[:danger] = "Invalid resident key."
# render 'new' doesn't work
# render action: 'new' doesn't work
redirect_to new_visitor_pass_path works
redirect_to '/visitor_passes/new' works
return
end
.
.
.
end
end
Here is the output of the console.
Rendering visitor_passes/new.html.erb within layouts/application
Rendered visitor_passes/new.html.erb within layouts/application
Rendered layouts/_rails_default.html.erb
Rendered layouts/_shim.html.erb
Resident Load (0.3ms) SELECT "residents".* FROM "residents" WHERE "residents"."id" = ? LIMIT ? [["id", 155], ["LIMIT", 1]] app/helpers/sessions_helper.rb:17:in 'current_user'
Rendered layouts/_header.html.erb (Duration: 3.1ms | Allocations: 760)
Completed 200 OK in 429ms (Views: 59.6ms | ActiveRecord: 2.3ms | Allocations: 33936)
Flash messages are displayed in the next response cycle (ie after a redirect). If you want to display a flash message in response to the current request use ActionDispatch::Flash::FlashHash#now.
class VisitorPassesController < ApplicationController
def new
#visitor_pass = VisitorPass.new
# just use the controller_name method provided by rails instead
end
def create
# ...
# prefer positive conditions instead of negative
if resident && correct_resident_key?
# do something awesome
else
flash.now[:danger] = "Invalid resident key."
render :new
end
end
end
Also make sure you are using the local: true option on the form if using form_with as it defaults to those pesky XHR remote: true requests.
I have a problem where my controller action is creating duplicate records. I have a search form that checks the database for a record, or if its not in the database, scrapes a website to create the record. This same action (not restful i know) is also creating a record of the search itself with a value of "success" or "failure" depending on if the record could be found. However, it is consistently duplicating the record of the search. Here is the form_tag:
<%= form_tag new_search_path, remote: true, method: :get, id: 'etf-lookup-form' do %>
...
<%= text_field_tag :etf, params[:etf], placeholder: "ETF ticker symbol EX: SPY", autofocus: true, class: 'form-control search-box input-lg', style: "text-transform: uppercase" %>
and the controller:
class SearchesController < ApplicationController
def new
if params[:etf]
#etf = Etf.find_by_ticker(params[:etf].upcase)
#etf ||= Scraper.new_from_lookup(params[:etf].upcase)
end
if #etf.present?
Search.create(ticker: params[:etf].upcase, user_id: current_user.id, status: "success" )
render :js => "window.location = '#{etf_path(#etf)}'"
else
Search.create(ticker: params[:etf].upcase, user_id: current_user.id, status: "failure" )
render :js => "window.location = '#{search_path}'"
end
end
The terminal output always shows the get request being made twice before rendering the new page. How can I solve this problem? And/or what is a better way to organize these controller actions? I also have an EtfsController which contains a show action. Here are a couple fragments of from the terminal:
Started GET "/search/new?utf8=%E2%9C%93&etf=spy&button=" for ::1 at 2017-05-01 20:05:49 -0400
Processing by SearchesController#new as JS
Parameters: {"utf8"=>"✓", "etf"=>"spy", "button"=>""}
.......
Completed 200 OK in 10ms (Views: 0.1ms | ActiveRecord: 2.0ms)
Started GET "/search/new?utf8=%E2%9C%93&etf=spy&button=" for ::1 at 2017-05-01 20:05:49 -0400
Processing by SearchesController#new as JS
...
Completed 200 OK in 9ms (Views: 0.1ms | ActiveRecord: 2.7ms)
Started GET "/etfs/1" for ::1 at 2017-05-01 20:05:49 -0400
Processing by EtfsController#show as HTML
...
Completed 200 OK in 126ms (Views: 117.9ms | ActiveRecord: 1.2ms)
Probably you can refactor your code to look like this and the problem should be gone:
before_action :set_etf, only: [:new]
after_action :create_search, only: [:new]
def new
render js: window_location
end
private
def create_search
Search.create(ticker: etf_params, user_id: current_user.id, status: "success" )
end
def etf_params
#etf_params ||= params[:etf].to_s.upcase
end
def set_etf
#etf = (Etf.find_by_ticker(etf_params) || Scraper.new_from_lookup(etf_params) if etf_params.present?
end
def window_location
return "window.location = '#{etf_path(#etf)}'" if #etf.present?
"window.location = '#{search_path}'"
end
This should do the trick, let me know how it goes!
I receive POST request from third party URL and update the data to my DB.
In config/environments/production.rb, I have:
config.force_ssl = true
Now when I receive the request the following error was occurred in my console.
Started POST "/delivery_details" for 35.355.466.466 at 2015-07-20 17:11:51 +1000
Processing by DeliveryDetailsController#create as HTML
Parameters: {"data"=>"{\"numbers\":{\"911234567890\":{\"desc\":\"MESSAGE\",\"status\":1,\"userId\":\"35534\",\"senderId\":\"qwerty\",\"date\":\"2015-07-20 12:41:59.0\"}},\"requestId\":\"12345566778\"}"}
Completed 401 Unauthorized in 1ms
Started GET "/users/sign_in" for 35.355.466.466 at 2015-07-20 17:11:51 +1000
Cannot render console from 35.355.466.466! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by Devise::SessionsController#new as HTML
Rendered devise/sessions/new.html.erb within layouts/application (55.3ms)
Rendered layouts/_header.html.erb (3.9ms)
Rendered layouts/_menu.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (7.5ms)
Completed 200 OK in 82ms (Views: 78.6ms | ActiveRecord: 0.0ms)
My controller:
class DeliveryDetailsController < ApplicationController
skip_before_action :verify_authenticity_token
def index
updateSmsDeliveryStatus
end
def updateSmsDeliveryStatus
destinationType = "SMS"
json = JSON.parse(params["data"])
requestId = json["requestId"]
numbers = json['numbers']
numbers.each do |num|
#delivery_detail = DeliveryDetail.where(sms_request_id: requestId, destination_value: num[0].to_s,
destination_type: destinationType)
.update_all(:is_success => num[1]["status"], :sent_date => num[1]["date"])
end
end
end
I suppose that you have in your application controller the next line:
before_filter :authenticate_user!
So in your controller you need to skip this authentication:
skip_before_filter :authenticate_user!
And I don´t see in your controller the action create so maybe you receive a 404 error after this