Friendly ID Random Url - ruby-on-rails

I am using friendly for my site, and at the moment I have it displaying the title in the url
ie: /articles/hello-world
but say when i create the page, it generates a random number, to avoid duplication
so
ie: /articles/75475848
I know if i get rid of friendly id it will display numbers but
it will be
/articles/1
/articles/2
etc...
Basically how do i get it to show /articles/23456789(random number) instead of /articles/hello-world
Thanks

It seems that generating a UUID (Universally Unique Identifier) for each article might be a good solution for you.
The Ruby standard library gives us a UUID-generating method, so all you need to do is create a database field and then use a before_save callback to give each article its own UUID. Like this:
class Article < ActiveRecord::Base
before_save :set_uuid
def set_uuid
self.uuid = SecureRandom.uuid if self.uuid.nil?
end
end
Edit: No need for external dependencies as per #olleolleolle's comment!

From the FriendlyID docs:
class Person < ActiveRecord::Base
friendly_id :name_and_location
def name_and_location
"#{name} from #{location}"
end
end
bob = Person.create! :name => "Bob Smith", :location => "New York City"
bob.friendly_id #=> "bob-smith-from-new-york-city"
So, if you provide a method for friendly_id that generates a random number that method will be used to generate the slug instead.

Related

FriendlyID for child

I have a Project model that belongs to a User. A User has_many Projects. I have setup FriendlyID according to the gem instructions for User model, however it is not working in this scenario.
<%= link_to gravatar_for(project.user, size: 50), project.user %>
The above creates a link with the numerical ID of the user (project.user) instead of a friendly URL (i.e. http://localhost:3000/users/102 instead of what I want, http://localhost:3000/users/*random-gen-string*).
User.rb file:
class User < ApplicationRecord
extend FriendlyId
friendly_id :generated_slug, use: :slugged
def generated_slug
require 'securerandom'
#random_slug ||= persisted? ? friendly_id : SecureRandom.hex(15)
end
I think the problem is that project.user is set in the projects_controller.rb to the user ID (via current_user.projects.build...). If I could somehow access the Friendly ID for User in the projects_controller.rb I may be able to save it in the database and access it like project.user_friendly_id. Not sure..
Relevant code in projects_controller:
def create
#project = current_user.projects.build(project_params)
# code
end
What is the best way to go about making the above link link to the Friendly ID and not the user (i.e. http://localhost:3000/users/*random-gen-string* is what I want instead of http://localhost:3000/users/102)?
Update:
As discussed in the chatroom, User.find_each(&:save!) reveals the errors when saving the User model. In the above case, the lack of password input was preventing the User records from being saved. Removing the validation temporarily allowed saving the User and thus regenerating slugs.
(Original answer left for history)
You can override the to_param method in your User model like this
class User < ApplicationRecord
# some code
def to_param
slug
end
And then that is used to generate the link. More on that in the guides.
When you build your link_to you can call the user.slug to ensure that you get the proper info
<%= link_to gravatar_for(project.user, size: 50), project.user.slug %>
that will generate the link that you are expecting http://localhost:3000/users/random-gen-string
Here is an example of cities with increasing order of specificity.
def slug_candidates
[
:name,
[:name, :city],
[:name, :street, :city],
[:name, :street_number, :street, :city]
]
end
In case of conflicting slugs it is better to use user-friendly names then UUID (e.g. 2bc2-d3dd-4f29-b2ad)

slug candidates rails 4

I have Job model and Location model in my rails application. I am using postgresql as a database.so i have location_ids as an array field in my Job model for holding locations. I am using FeriendlyId in my application to make my url friendly. when i go to my job show page i am getting this friendly url
http://localhost:3000/jobs/seo-trainee
but now i also want to include the locations the job has in my url , something like this
http://localhost:3000/jobs/seo-trainee-mumbai-tokyo
i know we can use slug_candidates for this purpose. but i dont know how can i achieve this exactly
currently i have this in my Job model
extend FriendlyId
friendly_id :slug_candidates, use: [:slugged, :finders]
def slug_candidates
[
:title,
[:title, :id]
]
end
You need to define a custom method to generate your slug definition, and then tell FriendlyId to use that method.
The documentation gives this example:
class Person < ActiveRecord::Base
friendly_id :name_and_location
def name_and_location
"#{name} from #{location}"
end
end
bob = Person.create! :name => "Bob Smith", :location => "New York City"
bob.friendly_id #=> "bob-smith-from-new-york-city"
So in your case, you would use something like this:
class SomeClass
friendly_id :job_name_and_location
def job_name_and_location
"#{name} #{locations.map(&:name).join(' ')}"
end
end
I've made a few assumptions:
Your job model has a name attribute (seo training)
Your job model has_many locations, each of which have a name attribute
We then create a method which defines the non-friendly string which FriendlyId will use to create a slug from. In this case it'll come up with something like SEO Training Mumbai Tokyo and use that to create your seo-training-mumbai-tokyo slug.
You can use something like the following:
extend FriendlyId
friendly_id :slug_candidates, use: [:slugged, :finders]
def slug_candidates
locs = Location.where("id IN(?)", self.location_ids).collect{|l| l.name}.join("-") // here, we find the locations for the current job, then joins the each locations name with a '-' sign
return self.title+"-"+locs // here, returns the job title with the location names
end
So, if your current Job holds location_ids = [1,2,3]
then from Location table we find the locations with id = 1,2,3. Then join their names.

Rails: Validate uniqueness of admin_name based off of user_name column in a different table

I have two tables: admin_users and users. I want all the created names to be unique (a regular user can't create a name already taken by an admin user and vice-versa). I'm having trouble writing a validates_uniqueness_of validation that is able to analyze information in a different table. I think I have to use a scope of some sort, but I tried all sorts of combinations and couldn't get it to work. To be clear: I'm looking for the correct code to replace the question marks below.
validates_uniqueness_of :user_name, :scope => #???Look in admin users
#table and check to make that this name is not taken.
Any help would be very much appreciated. Thanks!
You can create a custom validator for this.
class UserNameValidator < ActiveModel::Validator
def validate(record)
if AdminUser.exists?(user_name: record.user_name)
record.errors[:base] << "An admin user have this username!"
end
end
end
class User < ActiveRecord::Base
validates_with UserNameValidator
end

Rails renaming the routing

I am trying to rename the routing of my email inputs for my rails app. Currently, when someone inputs their email, it routes them to /:controller/:id
I want to do it such that once they input their email, it won't show their id so they cannot change the id number and see other people's emails.
I think, use a permalink with some alphanumeric give secure email from another. for Assumes you have people model.
You only need to add one attribute to people, attribute name is permalink
try run
rails g migration add_permalink_to_peoples permalink:string
rake db:migrate
On people.rb , play with before_save
class People < ActiveRecord::Base
attr_accessible :email, :permalink
before_save :make_it_permalink
def make_it_permalink
# this can create permalink with random 8 digit alphanumeric
self.permalink = SecureRandom.base64(8)
end
end
And your routes.rb
match "/people/:permalink" => 'peoples#show', :as => "show_people"
on peoples_controller.rb
def show
#people = People.find_by_permalink(params[:permalink])
end
Run rails server and add one people.
People have a unique permalink with random 8 digit alphanumeric (e.g /people/:permalink)
example : http://localhost:3000/people/9sd98asj
EDIT:
i was trying my self and this dosn't works if its an email, but if you try it with a username with no special carracters it will work fine !
try something like this:
routes:
match "/controller/:username" => "controller#show"
controller:
def show
#user = find_by_username(params[:username])
end

How do I create custom "association methods" in Rails 3?

I've read this article, but it's for Rails 1.x.
I'd really like to create my own association methods:
user = User.find(1)
# Example of a normal association method
user.replies.create(:body => 'very informative. plz check out my site.')
# My association method
user.replies.find_by_spamminess(:likelihood => :very)
In Rails 3, what's the proper way of doing this?
The Rails 3 way of doing things is often to not use find methods, but rather scopes, which delays the actual database call until you start iterating over the collection.
Guessing at your first example, I would do:
in class Reply ...
scope :spaminess, lambda {|s| where(:likelyhood => s) }
and then using it:
spammy_messages = user.replies.spaminess(:very)
or to use it in a view
spammy_messages.each do |reply|
....
end
I think I found it!
If you search for "association extensions" the Rails API page for ActiveRecord::Assications, you'll see that this is the syntax (copied from that link):
class Account < ActiveRecord::Base
has_many :people do
def find_or_create_by_name(name)
first_name, last_name = name.split(" ", 2)
find_or_create_by_first_name_and_last_name(first_name, last_name)
end
end
end

Resources