On my web app I have a login page which is in the Pages Controller called welcome.html.erb
Inside it has a simple form for login and a simple for for sign up, both on the same page.
If the user signs up with wrong credentials (like password confirmation wrong, or length of password and etc) the controller that handles this is the new method in the Users Controller.
Inside the new method it checks if a user is created, and if not I'd like it to return to the welcome method in Pages Controller, passing to it the errors that were created during the user's creation.
It seems that if I do a
redirect_to root_path
The error count of the signup is reset when returning to the root page. If instead I call some other action of the users controller I do see the errors.
But since all of the html code is in the welcome view I don't want to replicate the code in the users controller views as well..
Is there a way to pass that errors data to the pages controller?
The partial for the error is
<% if object.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this <%= object.class.to_s.underscore.humanize.downcase %> from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Which I call using
<%= render 'shared/error_messages', :object => f.object %>
redirect_to welcome_path
(Or whatever the actual path is.)
From the Users controller I called
flash[:errors]=#user.errors
and then I changed the partial to be
<% if object.any? %>
<div id="error_explanation">
<h2><%= pluralize(object.count, "error") %> prohibited this <%= object.class.to_s.underscore.humanize.downcase %> from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% object.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Which I called using
<%= render 'shared/error_messages', :object =>#user_errors %>
That solved the issue for now..
Related
In my index view, I'm iterating over a list of bookings.
Also, I added a dropdown menu with the option to sort by created_at: asc and created_at: desc.
index.html.erb
<div class="dropdown">
<button class="btn" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Sort by
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<p> <%= link_to "ASC", sort: :asc %> </p>
<p> <%= link_to "DESC", sort: :desc %> </p>
</div>
</div>
<% #bookings.each do |booking| %>
<%= booking.address %>
<%= booking.created_at %>
<% end %>
This is the way I am sorting the #bookings in the controller:
booking_controller.rb
class Users::BookingsController < ApplicationController
def index
#bookings = current_user.bookings.order(created_at: params[:sort])
end
end
I'm not really sure if this is the best solution and if it has some vulnerability in terms of SQL injections...
Generally using params for order is unsafe, see https://rails-sqli.org/#order
You can use sanitize_sql_for_order to sanitaze input for ActiveRecord#order
Passing key/value pairs to order(created_at: params[:sort]) is safe. Rails validates the direction. If you give it an invalid direction it will raise ArgumentError: Direction "..." is invalid. It's been this way since the syntax was introduced in Rails 4.
Passing a string to order as in order("created_at #{params[:sort]}") could be exploited in Rails 5 and earlier. See Rails SQL Injection for details. Rails 6 now sanitizes order arguments and will raise an exception if it detects funny business.
Rails 6, in general, is more robust against SQL injection. But it's up to you to sanitize your inputs before passing them to anything which accepts raw SQL.
Your view is not turning the bookings into a drop down menu. Instead, it's just a bunch of text. As lurker suggested, use a function like collection_select to generate the select and option tags for you.
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, proc { |b| "#{b.address} #{b.created_at}" , prompt: true %>
<%= f.submit %>
<% end %>
To tidy that up a bit, you can add a method to Booking to produce the label you want and replace the proc.
class Booking
def dropdown_value
"#{address} #{created_at}"
end
end
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, :dropdown_value, prompt: true %>
<%= f.submit %>
<% end %>
I tried both these:
<% #candidates.each do |candidate| %>
<h4> <%=candidate.full_name %></h4>
<p>Links: <%= link_to "facebook", "#{candidate.link1}" %> </p>
<% end %>
<% #candidates.each do |candidate| %>
<h4> <%=candidate.full_name %></h4>
<p>Links: <%= link_to "facebook", "candidate.link1" %> </p>
<% end %>
With the first one, the string interpolation, I get returned an facebook, ignoring the second part of the link_to altogether.
With the second one, where the link1 is an attribute of the class Candidate, I get an error No Route matches candidate.link1.
What syntax do I need so the second part of the link_to is seen as a url in the database (in this case: "https://facebook.com/......") instead of a route?
I am taking a rails class at my University and I am trying to create a search form which will show the results on the same page rather than show a different page of results. Is this something simple to do? I am creating a museum app with artifacts for each museum but I want the user to search artifacts from either page.
On my routes.rb I have
resources :artifacts do
collection do
get 'search'
end
end
On my museum index I have the code below that he gave us but not sure how to tweak the get routes for the same page.
<%= form_tag search_artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
<% if #artifacts %>
<p> <%= #artifacts.length %> matching artifacts. </p>
<h2> Matching Artifacts </h2>
<% #artifacts.each do |a| %>
<%= link_to "#{a.name} (#{a.year})", a %><br />
<% end %>
<% end %>
Yes, this is easy. Just have the index page return the search results if params[:search_text] is present - this way you don't need a new route or a different page.
class ArtifactsController < ApplicationController
def index
#artifacts = Artifact.search(params[:search_text])
end
end
class Artifact < ActiveRecord::Base
def self.search(query)
if query
where('name ILIKE ?', "%#{query}%")
else
all
end
end
end
So then your form looks like:
<%= form_tag artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
Edit:
So what you really want to do is any page you want to search, include a form which makes a request to that same page.
Then in each of those controller methods just put this line of code:
#artifacts = Artifact.search(params[:search_text])
and that will populate the #artifcats array with only artifacts that match the search query.
Try using "Ransack" gem. It can also perform some more powerful searches.
Im working on a rails app where a user has the ability to upload photos. When a user uploads their photos it will appear on their profile. Everything works great besides when there is no photos created then I am unable to view the user profile page because of the photo being nil.
here is my show method in the users_controller.rb
def show
#user = User.find_by_id(:id)
#photo = #user.photos.find(params[:id])
end
Here is my show.html.erb
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
How can I bypass this error?
The code for your action seems wrong...
It should be this:
def show
#user = User.find(params[:id])
##photo = #user.photos.find(params[:id])
end
I commented out the third line on purpose, because I'm not sure what it is you want to do there, yet.
The #user variable needs to be defined using params[:id], given that this is the show action for the UsersController, so the id for the user will be passed through as params[:id].
But then you go and use this to find the photo for the user, which is what confuses me... the Photo record's id attribute is probably not going to be the same as the User record's id attribute.
So what is it?
You can replace the code in your show.html.erb with this:
<% if #user.photos %>
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
<% end %>
The problem is, when the user doesn't have any photos, #user.photos returns nil so you have to check for that first.
I'm trying to build a form that will list all users and allow you to check the ones that you want to add to a team. Here's my first cut at the form:
<div id="add_team_mates">
<%= form_tag do %>
<%= will_paginate #users %>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= gravatar_for user, :size => 30 %>
<%= link_to user.name, user %>
<%= check_box_tag("add", user.id) %>
</li>
<% end %>
</ul>
<%= submit_tag "Add Team Mates", :action => "add_team_mates" %>
<% end %>
</div>
And, right now this is all that I have in the controller:
def add_team_mates
end
The problem is that if I check multiple users, I only get the last user.id rather than multiple is as I'd expect. Here's some example from the log:
Started POST "/teams/5" for 127.0.0.1 at 2011-04-14 15:28:13 -0700
Processing by TeamsController#add_team_mates as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"IHFDevfKES8NibbCMlRa1t9qHn4/ZMKalK1Kjczh2gM=", "add"=>"3", "commit"=>"Add Team Mates", "id"=>"5"}
Completed in 12ms
Any help on this would be greatly appreciated. Thanks!
All your checkboxes have the same name, change the line to
check_box_tag("add[]",user.id)
In the controller your parameters will be like so:
params[:add] = ['foo','bar','baz']