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.
Related
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
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!
It shows no errors to aid in locating and fixing the problem. I've checked the database file and it's still empty.
The submit button <div><%= f.submit "Create", class: "btn btn-normal" %></div>
The only thing that changes after submitting is the address. It changes from http://localhost:3000/cars/new to http://localhost:3000/cars
Everything else stays the same. How do i fix this?
Updated the question with the following;
Log
Started GET "/cars/new" for ::1 at 2020-01-26 14:44:53 +0000
(0.1ms) SELECT sqlite_version(*)
Processing by CarsController#new as HTML
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering cars/new.html.erb within layouts/application
Rendered cars/new.html.erb within layouts/application (Duration: 12.1ms | Allocations: 1210)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered shared/_navbar.html.erb (Duration: 0.7ms | Allocations: 103)
Rendered shared/_message.html.erb (Duration: 0.1ms | Allocations: 17)
Completed 200 OK in 496ms (Views: 471.7ms | ActiveRecord: 1.0ms | Allocations: 15750)
Started POST "/cars" for ::1 at 2020-01-26 14:45:06 +0000
Processing by CarsController#create as HTML
Parameters: {"authenticity_token"=>"Oom+xdVDc0PqSwLbLIEP0R8H6U38+v9ISVql4Fr/0WSxZGSrxzTHccsgghd1U30OugcUBAA1R4BtsB0YigAUtA==", "car"=>{"vehicle_type"=>"Sports", "car_type"=>"Private", "seat"=>"5", "colour_type"=>"Black", "transmission_type"=>"Automatic"}, "commit"=>"Create car"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering cars/new.html.erb within layouts/application
Rendered cars/new.html.erb within layouts/application (Duration: 7.2ms | Allocations: 1144)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered shared/_navbar.html.erb (Duration: 0.2ms | Allocations: 103)
Rendered shared/_message.html.erb (Duration: 0.1ms | Allocations: 17)
Completed 200 OK in 124ms (Views: 114.9ms | ActiveRecord: 0.4ms | Allocations: 14757)
Model app/models/car.rb
class Car < ApplicationRecord
belongs_to :user
validates :vehicle_type, presence: true
validates :car_type, presence: true
validates :seat, presence: true
validates :transmission_type, presence: true
validates :engine, presence: true
end
Controller app/controllers/cars_controller.rb
class CarsController < ApplicationController
before_action :set_car, except: [:index, :new, :create]
before_action :authenticate_user!, except: [:show]
def index
#cars = current_user.cars
end
def new
#car = current_user.cars.build
end
def create
#car = current_user.cars.build(car_params)
if #car.save
redirect_to listing_car_path(#car), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
end
def show
end
def listing
end
def pricing
end
def description
end
def photo_upload
end
def features
end
def location
end
def update
if #car.update(car_params)
flash[:notice] = "Saved..."
else
flash[:notice] = "Something went wrong..."
end
redirect_back(fallback_location: request.referer)
end
private
def set_car
#car = Car.find(params[:id])
end
def car_params
params.require(:car).permit(:vehicle_type, :car_type, :seat, :transmission_type, :engine, :fuel_type, :colour_type, :window_type, :listing_name, :summary, :is_tv, :is_air, :is_internet, :is_sunroof, :is_bluetooth, :is_dvd, :is_gps, :is_usb, :is_audio, :is_airbags, :price, :active)
end
end
TLDR:
Solution is that you should either provide engine and user_id in params or you should remove presence true validation and add optional true case (for user association) from model.
Explanation:
If your model says that it should validate presence of engine then how can you not provide engine param (in form). When you post the form without engine, what happens is that your model does not save it and as you have handled that case, it moves on. As it belongs to user, same goes for user ID. although you could make it optional too by adding optional: true both in schema and model (because a car can "be" without a user IRL but depends here in your use-case).
Going one step further, to exactly understand the issue yourself, use pry or byebug to see the params and happenings in runtime. Easier and faster way to verify the error is that put a bang in front of create method and it will show the error like: if #car.save!. One more thing: copy the car params and try to do this in rails console yourself manually with bang. It will give you the cause. These things will help you diagnose model save/create issues in rails.
Happy Coding :)
From your log file
Started POST "/cars" for ::1 at 2020-01-26 14:45:06 +0000
Shows that the create action is being called on the cars controller
The parameters being passed in are
{"authenticity_token"=>"Oom+xdVDc0PqSwLbLIEP0R8H6U38+v9ISVql4Fr/0WSxZGSrxzTHccsgghd1U30OugcUBAA1R4BtsB0YigAUtA==", "car"=>{"vehicle_type"=>"Sports", "car_type"=>"Private", "seat"=>"5", "colour_type"=>"Black", "transmission_type"=>"Automatic"}, "commit"=>"Create car"}
The first method called on your create action is authenticate_user
before_action :authenticate_user!, except: [:show]
You can see that this happens
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 1], ["LIMIT", 1]]
According to your log the next thing that happens is
Rendering cars/new.html.erb within layouts/application
Which means that the else clause was hit render :new, notice: "Something went wrong..."
#car = current_user.cars.build(car_params)
if #car.save
redirect_to listing_car_path(#car), notice: "Saved..."
else
render :new, notice: "Something went wrong..."
end
Therefore the car did not save so validation must have failed.
Your new car form should have an errors loop to display all the errors. If it did have this then your user (You) would know what went wrong
Something like this
<% if car.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(car.errors.count, "error") %> prohibited this car from being saved:</h2>
<ul>
<% car.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
Should do the trick but it's standard in all rails generated forms so it should be there anyway
NOTE: I'm not using Devise.
I'm implementing a password reset action and I have the controller Password_Resets with the following edit action:
def edit
end
def update
puts "I'm in the update!!"
if params[:user][:password].empty?
#user.errors.add(:password, "can't be empty")
render 'edit'
elsif #user.update_attributes(user_params)
log_in #user
flash[:success] = "Password has been reset."
redirect_to recipes_url
else
render 'edit'
end
end
When I'm trying to run through it, I put in the appropriate URL and I get the following response:
Started GET "/password_resets/igArFj9sYLt1J6k6Y2BjSg/edit?email=maggie%40example.com" for ::1 at 2016-04-20 21:49:58 -0500
Processing by PasswordResetsController#edit as HTML
Parameters: {"email"=>"maggie#example.com", "id"=>"igArFj9sYLt1J6k6Y2BjSg"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1 [["email", "maggie#example.com"]]
Redirected to http://localhost:3000/
Filter chain halted as :valid_user rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.1ms)
Why is it redirecting to localhost rather than the view app/views/password_resets/edit?? I can't seem to figure out a good way to "debug" this or see what's going on.
NOTE: I made that view incredibly simple to make sure it wasn't redirecting.
This is the view app/views/password_resets/edit:
<h1>This is my edit view </h1>
EDIT::: SOLUTION
So I was just an idiot. Essentially I have a validated user command that checked if the user was authenticated and the user was not. Therefore I need some more error handling.
Thanks you!!
The error is in your validations:
Filter chain halted as :valid_user rendered or redirected
I'm assuming you are calling this at the top of your controller
You can see in your web server logs:
Filter chain halted as :valid_user rendered or redirected
It's mean you have before_filter or before_action in a controller.
This filter is just ruby method - def valid_user and obvious that it contains a condition with redirect.
You need to debug this method.
You can read more about controller filters here
I'm running into a perplexing issue that I can only resolve partway, and hopefully, someone more experienced can tell me whether I can achieve what I wish, or if I'm barking up the wrong tree.
I have a Rails 4 application which uses Devise and CanCan. I'd like to make a small subset of application functionality available to guest users (not logged in). I can achieve this by specifying a get route to a controller method and using link_to to reach that method. I cannot, however, figure out how to get the value of a select box to pass along as parameters on that page without making that view a form using form_tag (there is no model associated with this view).
I can pass hardcoded params along like so:
<%= link_to "Month", activities_search_month_path(:resource_id => 4) %>
but I'd rather have something like:
<%= link_to "Month", activities_search_month_path(:foo => :resource_id) %>
where the second symbol refers to the value of a select_tag. This second example delivers a literal value of "resource_id" when I dump the :foo key unless I convert my view to a form.
If I turn the view into a form by enclosing all the erb in a form_tag, I get a 401 Forbidden error, after which the Devise sign in form is rendered. My guess is that any time you want to process a form, Rails (or Devise) demands authentication on some level. The behavior is the same when I use button_to rather than link_to, since button_to wraps itself in a form under the covers.
How can I set that resource_id argument in my link_to, or will I be forced to create a guest user access level and silently log in guest users? It's important for the UX that users can access this functionality with the least amount of effort possible.
Thanks in advance.
Addendum: quick_search method from controller
def quick_search
puts "quick search 0"
if(params[:time_period] == 'today')
#resource = Resource.find(params[:resource_id])
#site = Site.find(params[:site_id])
#time_period_string = "Activities for #{localize_date(Date.today)} at #{#resource.name}, #{#site.name}"
puts "quick search 1"
if user_signed_in?
puts "quick search 2a"
#activities = Activity.where("system_id = ? and start_date = ? and activity_status_id = ? and resource_id = ?", current_system_id, #today, 2, params[:resource_id])
else
puts "quick search 2b"
if(Setting["#{current_subdomain_not_signed_in}.quick_search_guest_access"] == 'true')
puts "quick search 3a"
current_system_id = current_system_id_not_signed_in
#activities = Activity.where("system_id = ? and start_date = ? and activity_status_id = ? and resource_id = ?", current_system_id, #today, 2, params[:resource_id])
else
puts "quick search 3b"
redirect_to '/users/sign_in'
end
end
end
Note: the quick_search method is never entered. CanCan (or maybe Devise) steps in immediately and redirects to sign in:
Console output:
Started GET "/activities/quick_search" for 127.0.0.1 at 2015-04-12 18:01:58 -0700
Processing by ActivitiesController#quick_search as HTML
(0.2ms) SELECT DISTINCT "systems"."subdomain" FROM "systems"
Completed 401 Unauthorized in 1ms
Started GET "/users/sign_in" for 127.0.0.1 at 2015-04-12 18:01:58 -0700
Processing by Devise::SessionsController#new as HTML
(0.2ms) SELECT DISTINCT "systems"."subdomain" FROM "systems"
Rendered layouts/_header.html.erb (0.8ms)
Rendered devise/shared/_links.html.erb (4.1ms)
Rendered devise/sessions/new.html.erb within layouts/application (14.7ms)
Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 285ms (Views: 282.3ms | ActiveRecord: 0.2ms)
Ability.rb
can :quick_search, Activity
can :search_day, Activity
can :search_week, Activity
can :search_month, Activity
The odd thing is that link_to quick_search fails with a 401, but link_to the other three methods works fine -- I just can't get parameters to them dynamically.
If you are using CanCan(Can?) you can define a special ability for guests.
How does your Ability-model look?
Which controller are handling the action that you want to view?
How do you authenticate with CanCan in this controller?
https://github.com/CanCanCommunity/cancancan/wiki/CanCan-2.0
Under the "Defining Abilities" you can see a non-user example.
Fixing CanCan is probably the best option, if you do not want to:
For the part with the link and select box it would be easiest to handle as a form and then handle the redirect in the controller, it could also be done with a remote ajax form.
http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html
This should work:
<% form_tag Activity, activity_quick_search_path, remote: true do %>
<%= select_tag :resource_id...%>
<%= submit_tag %>
<%end%>
Edit after comments:
The culprit here is(was) an:
before_action :authenticate_user!
Causing Devise to redirect to sign in page.
However, if you have CanCan you shouldn't need the authenticate_user.
Short example:
With only Devise I would do:
class NewsController < ApplicationController
before_action :authenticate_user!
before_action :set_news, except: [ :index, :new ]
def index
#news = News.all
end
def show
end
def new
#news = News.new
end
def edit
end
def create
#news = News.new(news_params)
flash[:notice] = 'News created' if #news.save!
redirect_to #news
end
def update
#news.update! news_params
redirect_to #news
end
def destroy
#news.destroy!
redirect_to News
end
private
def news_params
params.require(:news).permit(some_attributes)
end
def set_news
#news = News.find(params[:id])
end
end
How it looks with CanCanCan:
class NewsController < ApplicationController
load_and_authorize_resource
def index
end
def show
end
def new
end
def edit
end
def create
flash[:notice] = 'News created' if #news.save!
redirect_to #news
end
def update
#news.update! news_params
redirect_to #news
end
def destroy
#news.destroy!
redirect_to News
end
private
def news_params
params.require(:news).permit(some_attributes)
end
end
Which I find super neat 😄
Hope that this can help as well.