In my rails application I currently have a load of users who each have a registered user id.
If I go in to my users index and click on a users show page I get the following example header.
localhost:3000/users/3
Now I don't like this as it easily allows people to skip through users in the header.
How would I go about doing the following so that it shows the user.username field instead e.g.
localhost:3000/users/adamwest
You can define a to_param method on the User model.
class User
...
def to_param
name
end
...
end
Then every generated URLs will have name instead of id as a user identifier.
sid = User.new :name => 'sid'
user_path(sid) #=> "/users/sid"
Of course, in the controller, you have to find user by name.
class UsersController
...
def show
#user = User.find_by_name(params[:id])
end
...
end
I also suggest you to take a look at friendly_id gem.
FriendlyId is the “Swiss Army bulldozer” of slugging and permalink
plugins for ActiveRecord. It allows you to create pretty URL’s and
work with human-friendly strings as if they were numeric ids for
ActiveRecord models.
Related
this is my model User
class User < ApplicationRecord
extend FriendlyId
friendly_id :name
end
the user name is not uniq.
i want my url like this:
http://localhost:3000/users/myname
this is my controller:
class UsersController < ApplicationController
before_action :set_user
def set_user
#user = User.friendly.find(params[:id])
end
end
the URL is shown fine, just the way i want, but the problem is when i try to delete a user, the console server shows a "rollback" i notice that this is because there are two or more users with the same name so It can delete the user.
So my problem now that I have implemented gem friendly_id is that it searchs and set_user by name but i want to set_admin by ID so i can delete by id (this way it does not matter if there are many users with the same name). This problem is repeated in my other models too.
How can avoid this behavoir, I need to set model by id but to show the name or encrypt the id in the url. Do you recomend me other gem or how should i implement correctly. (is not an option to set name as uniq). thanks
As per my understanding,
friendly id uses uniqueness validation at db level
https://github.com/norman/friendly_id/blob/aff0564584e84ffa505e6e278b65ca3c4ee5d698/lib/friendly_id/migration.rb#L12
If you already have users with same name, you should delete those entries.
(This is much similar to condition where we try to put unique index to a column in db where same entry values already exist)
Then install friendly_id gem, and make entries. I am sure slugs created by gem wont repeat so every record will be unique and you will be able to delete record using id Too
Here's the scenario to illustrate my question. I have 2 models:
# models/post.rb
belongs_to :user
validates_presence_of :comment
And we have a devise model called Users
# models/user.rb
has_many :posts
What I would like to achieve:
Person comes to the website, is able to create a Post, after creating the Post, they are prompted to create an account. After creating the account, the Post that they just created would be associated to the User they just created.
Usually i'd make use of routes to hold the params[:id] which can be accessed in the controller method. For example the URL may look something like this:
www.foo.com/foo/new/1
And then I can do this:
# foo_controller.rb
def new
#foo = Foo.new
#parent = Parent.find(params[:id])
end
And in the view I can simply access #parent and use a hidden field to fill the parent ID.
But when routing through so many different pages (such as creating a Devise User), how do I hold onto the parent/child ID such that I can still create that association?
Using an hidden field or the route to store the id, with no authorization in the process, would not be secure. What if I just use the browser inspector and change the value of the id ? Your cool post would be mine.
What you could do is, for instance, add a field called guest_id to the Post, in which the value is unique (like SecureRandom.uuid), and also store that value in the session.
Thus, after the user is created, you could do something like that
if (post = Post.find_by(guest_id: session[:guest_id])).present?
post.update(user_id: current_user.id)
end
Rails 3.2
I am using the API gem. What the client wants, is to keep the table where he wants to whitelist the email addresses that can be used to access the API, in a seprate table, that he only can access through phpmyadmin.
This would be a single table:
api_users
With a single column: email (in addition to id, created_at, updated_at)
The email addresses that would go in this table, also exist in the users table for the rails application.
If I create a model: models/api_user.rb:
class ApiUser< ActiveRecord::Base
attr_accessible :email
And, in my models/api_ability.rb, I add the following:
class ApiAbility
include CanCan::Ability
def initialize(user, params = {})
user ||= User.new
if ApiUser.find_by_email(user.email)
can :manage, :api
end
end
end
Will this work?
That sounds absolutely doable. You might want to add something like
def readonly?
true
end
to the ApiUser class to make sure no one will try to create instances of it from within Rails. But apart from that I don't see any reason not to do it that way given the clients requirements.
for now when i click user with id = 1, on url bar its
users/1
I want to change it to
users/[encrypt]
or
users/some_user
is there any way to do that on rails?
What about using a permalink instead of the users id? i.e. users/[permalink] and you can configure the permalink to anything you like as long as it is a unique value
Checkout the friendly_id gem: https://github.com/norman/friendly_id
Rails uses to_param method when displaying object in url.
If you change to_param method in user it will, be used to display data instead of id.
By default rails has implemented to_param to return id of the object.
For example
class User < ActiveRecord::Base
...
def to_param
"#{self.first_name}-#{self.last_name}" # or whatever you want to use
end
...
end
In your url you will have /users/first_name-last_name or whatever your to_param method returns. By default to_param returns id and in url you get /users/4. and in your controller you can find user with id 4, but when you change to_param method, you have to change respectively the way you fetch user from database.
Example:
I change my to_param method to return nick_name from database, and it is unique for the particular user, that I can use to find user from database.
In router
change the mappings for params
get 'users/:nick_name', 'users#show'
In controller
User.find_by :nick_name => params[:nick_name]
like others in this post says , i use
i use
https://github.com/norman/friendly_id this way:
# app/models/secret.rb; this would go in the model you want to obfuscate
class Secret < ActiveRecord::Base
has_friendly_id :code, :use_slug => true
validates :name, :uniqueness => true
def code
Digest::SHA1.hexdigest self.name
end
end
it’s simple. If your security needs are serious you’d probably want something a little more complex (not to mention more layered than a basic obfuscation technique), but I wanted to share an out-of-the-box way to use a gem that already exists (and may even be in use in your app already)
I have a rails app, with two separate DB tables, users and products. A user has_many products, and a product belongs_to a user.
When I create a product, I want it to automatically add the user_id to the user_id database column in the products table. What changes to my mvc do I need to make to ensure that the correct user_id is added when a new product is created?
You can scope the creation of the new product through the user.
For example, instead of this:
Product.create(params[:product])
you do this:
current_user.products.create(params[:product])
where "current_user" is the user creating the product.
Just as a suggestion, you may want to go back and accept the answers to some of your previous questions, which will improve your response rate and increase the likelihood someone will answer your questions in the future.
There are a few ways to do this, one approach:
Create current user function
class ApplicationController < ActionController::Base
private
# Finds the User with the ID stored in the session with the key
# :current_user_id This is a common way to handle user login in
# a Rails application; logging in sets the session value and
# logging out removes it.
def current_user
#_current_user ||= session[:current_user_id] &&
User.find_by_id(session[:current_user_id])
end
end
http://guides.rubyonrails.org/action_controller_overview.html#session
Make sure to be cognizant of security concerns. A gem like Devise can also help.
Add to products controller
class ProductsController < ApplicationController
def create
current_user.products.create! params[:product] # make sure attr_accessible is setup on products
end
end