I want to let users have links to their profiles using their registered usernames.
I store their username exactly how they give it.
I set up my routes to match /:name and then used find_by_name to get it. The problem I have is when you type in example.com/username it doesn't work the name: Username. (Note the uppercase/lowercase difference)
So my question is how can I ignore case in urls?
You can store the username downcased along with a display_name which is in the format they gave it to you. Then, downcase any input and match it with username and only use display_name for, well, display :)
If you wanted, you could even redirect to /DisPlAyName from /username after you look up the record.
Easiest way is to convert the username in the database and in rails to lower (or upper) case when you are doing the comparison.
User.where('lower(username) = ?', params[:name].downcase).first
Or if you are still using rails 2:
User.find(:first, :conditions => ['lower(username) = ?', params[:name].downcase])
One way to do this is to store a lowercase version of their username. When they type in
example.com/UsErNaMe or example.com/Username
downcase it and match it to the lowercase version in the database.
---OR---
Just make the user have a lowercase username everywhere. (Downcase it when its made)
---OR---
Have a constant type of username. So always have the first letter capitalized or something. Store it as lower case and upcase the first letter everytime you show it.
Related
I have the cars_tables and in its name column I have names with special characters, for example:
car_names = Car.pluck :name
=> ["Cárrozería", "Óther Cars", "Forede Lúis", "Ságara Mbobe"]
The values are automatically parameterized making the special characters disappear
car_name_parameterize << ["Cárrozería", "Óther Cars", "Forede Lúis", "Ságara Mbobe"].map { |name| name.parameterize }.join(', ')
=> ["carrozeria", "other-cars", "forede-luis", "sagara-mbobe"]
and with the parameterized values I would like to do a query but I can't since the names have special characters that prevent me from doing so
first_car_name = car_name_parameterize.first
=> carrozeria
Car.find_by('name ILIKE ?', "%first_car_name%")
=> nil ;; nil because the word **carrozeria** doesn't have í special character,
Car.find_by_name "carrozería"
=> #<Car:0x300312318 id: 1, name: "carrozería"...> ;; If it does the query without returning nil but it is because I consulted its name manually when placing "carrozería"
In short, I am looking to make the queries with the columns with the same name but with special characters (usually these characters usually have accents) recognized.
I am looking to make queries to the name of the cars table, canceling the special characters, such as the accent between the words for example
I have also tried the gsub method without success.
If you could help me I would be very happy and thank you for taking the time to read me.
You will need to use the unaccent extension (docs: https://www.postgresql.org/docs/current/unaccent.html).
Basically, install the extension:
CREATE EXTENSION unaccent;
And then you will be able to use the unaccent() function:
where("unaccent(name) LIKE ?", "%#{your_value}%")
Read more details and different alternatives in the following entry: Postgres accent insensitive LIKE search in Rails 3.1 on Heroku
Thanks to the link that the user #markets shared with me, I used the unaccent method to avoid the settlements and then the lower case and it worked for me.
cart_name = "carrozería"
Car.find_by("lower(unaccent(name)) LIKE ?", "%#{cart_name}%")
I'm trying to understand SQL Injection. It seems like people can get pretty creative. Which gets me wondering about my search-based rails webapp I'm making.
Suppose I just fed user-entered information directly into the "where" statement of my SQL query. How much damage could be done to my database by allowing this?
def self.search(search)
if search
includes(:hobbies, :addresses).where(search)
else
self.all
end
So basically, whatever the user types into the search bar on the home page gets fed straight into that 'where' statement.
An example of a valid 'search' would be:
"hobby LIKE ? OR (gender LIKE ? AND hobby LIKE ?)", "golf", "male", "polo"
Does the fact that it's limited to the context of a 'where' statement provide any sort of defense? Could they still somehow perform delete or create operations?
EDIT:
When I look at this tutorial, I don't see a straightforward way to perform a deletion or creation action out of the where clause. If my database contains no information that I'm not willing to display from a valid search result, and there's no such thing as user accounts or admin privileges, what's really the danger here?
I took this from another post here: Best way to go about sanitizing user input in rails
TL;DR
Regarding user input and queries: Make sure to always use the active record query methods (such as .where), and avoid passing parameters using string interpolation; pass them as hash parameter values, or as parameterized statements.
Regarding rendering potentially unsafe user-generated html / javascript content: As of Rails 3, html/javascript text is automatically properly escaped so that it appears as plain text on the page, rather than interpreted as html/javascript, so you don't need to explicitly sanitize (or use <%= h(potentially_unsafe_user_generated_content)%>
If I understand you correctly, you don't need to worry about sanitizing data in this manner, as long as you use the active record query methods correctly. For example:
Lets say our parameter map looks like this, as a result of a malicious user inputting the following string into the user_name field:
:user_name => "(select user_name from users limit 1)"
The bad way (don't do this):
Users.where("user_name = #{params[:id}") # string interpolation is bad here
The resulting query would look like:
SELECT users.* FROM users WHERE (user_name = (select user_name from users limit 1))
Direct string interpolation in this manner will place the literal contents of the parameter value with key :user_name into the query without sanitization. As you probably know, the malicious user's input is treated as plain 'ol SQL, and the danger is pretty clear.
The good way (Do this):
Users.where(id: params[:id]) # hash parameters
OR
Users.where("id = ?", params[:id]) # parameterized statement
The resulting query would look like:
SELECT users.* FROM users WHERE user_name = '(select user_name from users limit 1)'
So as you can see, Rails in fact sanitizes it for you, so long as you pass the parameter in as a hash, or method parameter (depending on which query method you're using).
The case for sanitization of data on creating new model records doesn't really apply, as the new or create methods are expecting a hash of values. Even if you attempt to inject unsafe SQL code into the hash, the values of the hash are treated as plain strings, for example:
User.create(:user_name=>"bobby tables); drop table users;")
Results in the query:
INSERT INTO users (user_name) VALUES ('bobby tables); drop table users;')
So, same situation as above.
I hope that helps. Let me know if I've missed or misunderstood anything.
Edit Regarding escaping html and javascript, the short version is that ERB "escapes" your string content for you so that it is treated as plain text. You can have it treated like html if you really want, by doing your_string_content.html_safe.
However, simply doing something like <%= your_string_content %> is perfectly safe. The content is treated as a string on the page. In fact, if you examine the DOM using Chrome Developer Tools or Firebug, you should in fact see quotes around that string.
I've fought a few hours now to store a string in a database column in Rails.
I had to rename authorization to transaction so that Rails would store the value.
Why does Rails interfere while saving the value?
Example:
# Works
self.update_attribute(:transaction, result) rescue nil
# Does not work
self.update_attribute(:authorization, result) rescue nil
What is your underlying database? It might have "authorization" as a reserved word.
See the generated sql and run it directly to your db. If it runs without problems, then my assumption is invalid.
Both mySQL and SQLserver use authorization as a reserved word.
So you'll just need to use the different word.
You could also use something close like 'authorized' or 'auth'.
maybe try prefixing the column using the table name? For example:
UPDATE my_table
SET my_table.authorization = "new authorization"
WHERE id = 5
I'm developing a web application using rails.
For aesthetic purposes, i need to replace %20 with -
Before: http://localhost:3000/movies/2006/Apna%20Sapna%20Money%20Money
After: http://localhost:3000/movies/2006/Apna-Sapna-Money-Money
Is there anyway i can achieve this in rails?
You should use URI.parse to break it into pieces and then change only the path component:
require 'uri'
u = URI.parse(url)
u.path = u.path.gsub('%20', '-')
url = u.to_s
Just a simple gsub on the whole URL would probably work fine but a little extra paranoia might save you some confusion and suffering down the road. Also, if you're just replacing a literal string rather than a regular expression, you can use a String as the first argument to gsub and avoid some escaping issues:
The pattern is typically a Regexp; if given as a String, any regular expression metacharacters it contains will be interpreted literally, e.g. '\\d' will match a backlash followed by d, instead of a digit.
If your string is stored in the variable url you can use
url.gsub(/%20/, "-")
to return the string you want, or
url.gsub!(/%20/, "-")
to actually modify the value of url with the value you want.
https://github.com/FriendlyId/friendly_id
this is the best way to go about seo urls
You probably want to be saving "Apna-Sapna-Money-Money" within your Movies model as an attribute (I usually call these slugs). Then, to generate these, you might just need to replace spaces in the movie title with hyphens. Something like:
class Movie
before_create :generate_slug
private
def generate_slug
slug = title.gsub(" ", "-")
end
end
Then in your controller action you can simply do a Movie.find_by_slug!(params[:id]) call.
Basically, there should be no reason for users to ever arrive at a URL with %20 in it...
I want to give my pages human-readable slugs, but Rails' built-in parameterize method isn't SEO-optimized. For example, if I have a post called "Notorious B.I.G. is the best", parameterize will give me this path:
/posts/notorious-b-i-g-is-the-best
which is suboptimal since Google construes the query "Notorious B.I.G." as "Notorious BIG" instead of "Notorious B I G" (i.e., the dots are removed rather than treated as spaces)
Likewise, "Tom's fave pizza" is converted to "tom-s-fave-pizza", when it should be "toms-fave-pizza" (since Google ignores apostrophe's as well)
To create a better parameterize, I need to know which characters Google removes from queries (so I can remove them from my URLs) and which characters Google treats as spaces (so I can convert them to dashes in my URLs).
Better still, does such a parameterize method exist?
(Besides stringex, which I think tries to be too clever. 2 representative problem cases:
[Dev]> "Notorious B.I.G. is the best".to_url
=> "notorious-b-dot-i-g-is-the-best"
[Dev]> "No, Curren$y is the best".to_url
=> "no-curren$y-is-the-best"
I would try using a gem that has been designed for generating slugs. They often make good design decisions and they have a way of updating the code for changing best practices. This document represents Google's best practices on URL design.
Here is a list of the best gems for solving this problem. They are sorted by rank which is computed based on development activity and how many people "watch" changes to the gems source code.
The top one right now is frendly_id and it looks like it will generate good slugs for your use in SEO. Here is a link to the features of the gem. You can also configure it and it looks like it is perfect for your needs.
Google appears to have good results for both the "b-i-g" and "big" in the url slugs.
For the rails side of things, yes a parameterize method exists.
"Notorious B.I.G. is the best".parameterize
=> "notorious-b-i-g-is-the-best"
I think you can create the URLs yourself... something like
class Album
before_create :set_permalink
def set_permalink
self.permalink = name.parameterize
end
def to_params
"#{id}-#{permalink}"
end
end
This will create a url structure of:
/albums/3453-notorious-b-i-g-is-the-best
You can remove the id section in to_params if you want to.
Use the title tag and description meta tag to tell google what the page is called: these carry more weight than the url. So, leave your url as /posts/notorious-b-i-g-is-the-best but put "Notorious B.I.G. is the best" in your title tag.