Rails: Prevent id conflict with a method - ruby-on-rails

I am using string as id in routes (e.g. resource/:id ) but id can also be 'new' (a method in my Controller) which rather than showing the resource with id=new, directs to create new resource. How can I restrict users from choosing id=new while creating new resource?

I can think of three solutions where you can set string instead of id
First: set a combination of the id and the attribute_name, add
in your model
def to_param
return [self.id, self.attr_name].join('-')
end
Second: prevent the user of adding any action method in your controller (that's safer than restricting only the "new" method, you may add other get methods in the future)
validates :attr_name, exclusion: { in: YourController.action_methods.to_a }
Third:
use friendly_id gem

Try to use exclusion validation in the model, http://guides.rubyonrails.org/active_record_validations.html#exclusion

In config.rb, change your route to:
resources :resources
You'll get the routes you need. I have a feeling you'll soon need some of the others that come with it, like create and edit.
Edit: to make life easier, in your model:
def to_param
return self.my_string_id
end
Where my_string_id is the string you are using in the URL as the identifier. That will make the URL use that as the :id param instead of the numeric ID.
See: http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default

Related

Use multiple routes for same objects

In Rails the default routes use the internal database id to identify the resource, so you end up with routes like:
/user/1/widget/4
It's possible to change these to use something other than :id easily enough so that you could have routes like:
/user/bob/widget/favorites
But is there a way to have both available? I ask because in my case I'm using the route to create a unique id for use with an external service, but I'd like them to be based on a field other than id because it's more useful to pass these alternative ids to the external service.
I can of course build something custom, but we currently have some code that works as follows (with other convenience functions on top; this is the core functionality) to get most of the functionality I would have to build 'for free' from Rails:
class PathIdParser
def initialize
#context = Application.routes
end
def parse(path)
#context.recognize_path(path)
end
def build(route, params)
#context.named_routes[route].format(params)
end
end
Obviously the build function is easy enough to work with to use other routes by just changing the values passed into the params hash, but is there a way I can get parse to use these alternative fields to look up resources by, since recognize_path seems to work based on the values returned by to_param.
In routes.rb
get 'user/:username/widget/favourites', to: 'users#favourites'
This would route 'user/bob/widget/favourites' to the favourites action of the UsersController and you could access the username via
#username = params[:username]
Use the method to_param() in your model.
It returns a String, which Action Pack uses for constructing an URL to this object. The default implementation returns this record’s id as a String, or nil if this record’s unsaved.
class User < ActiveRecord::Base
def to_param
name
end
end
user = User.find_by_name('Richard')
user_path(user) # => "/users/Richard"

Rails - how to set up path to action by own criteria (not ID)

When I have a path like this:
user_messages_path(current_user)
it generates following URL:
users/1/listings
I am storing in database users' unique codes, so I wouldn't like to display URLs like
users/ID/listings
but more like
users/CODE/listings
How I need to update routes for using paths with users' codes?
Thanks
user_messages_path(current_user)
is a shortcut for:
user_messages_path(current_user.to_param)
which generally does:
user_messages_path(current_user.id)
You can:
pass any string you want: user_messages_path('foo')
or override to_param in your model
Just beware to update your code responsible to retrieve the object from the params.
in user.rb
def to_param
uuid # or whatever attribute you want to use instead of the id
end
in the controllers instead of User.find(params[:id]):
User.find_by_uuid!(params[:id]) # adjust to the attribute name used in to_param
You can use a custom route, something like the following.
get 'users/:code/:listings' => 'listings#index', as: :user_messages
Then in your params there key :code will return that part of the url e.g. params[:code]
In your controller you could use the following
Rails 3.2
User.find_by_code(params[:code])
Rails 4
User.where(code: params[:code])

Dynamically generated routes/URLs from Model fields in Rails 3

Describing the following scenario:
A user signs up and provides a firstName (john) and a lastName (jagger)
A route is automatically generated for the default domain i.e. www.asdasd.com/john.doe
A guest visits www.asdasd.com/john.doe and is taken to the 'view' action of the controller for this user
Is something like this possible? I do not know how to form something like this in routes.rb
Thanks!
Take a look at friendly_id. It doesnt generate routes dynamically but instead it lets u use the name as the ID.
Rails provides method in your models called to_param. This method returns URL for your model instance. For example: you have model User user = User.find_by_name('John')
user_path(user) # => /users/1
You can ovverride to_param method to return URL such as:
/users/John
Here you can read more:
http://apidock.com/rails/ActiveRecord/Base/to_param

Rails path tags conflicting, want urls like /post/some-title but when editing/updating use the ID not title

Having some issues, I want my urls for the show action to be like:
/post/some-title
i.e. so wherever I reference the show_post_path tag (or whatever it is) it should make that url.
BUT, when editing/updating I want to do this using the ID of the post ie.
/post/234/edit
How can I achieve this, it seems what I am doing is messing things up because I used:
def to_param
#{title}"
end
In my post model.
I always add an attribute called 'slug' to posts and it acts as a slug for that post.
Then just find your posts with Post.find_by_slug(params[:id]).
You can even make it translatable.
Create a to_param method. For example:
def to_param
"#{self[:id]}-#{title.gsub(/[^a-z0-9]+/i, '-')}"
end
Assuming the field you wanted to be in the URL is title, then your posts' URLs would be like /posts/1-this-is-a-post.

Permalinks with Ruby on Rails (dynamic routes)

I am currently developing a blogging system with Ruby on Rails and want the user to define his "permalinks" for static pages or blog posts, meaning:
the user should be able to set the page name, eg. "test-article" (that should be available via /posts/test-article) - how would I realize this in the rails applications and the routing file?
for user-friendly permalinks you can use gem 'has_permalink'. For more details http://haspermalink.org
Modifying the to_param method in the Model indeed is required/convenient, like the others said already:
def to_param
pagename.parameterize
end
But in order to find the posts you also need to change the Controller, since the default Post.find methods searches for ID and not pagename. For the show action you'd need something like this:
def show
#post = Post.where(:pagename => params[:id]).first
end
Same goes for the other action methods.
You routing rules can stay the same as for regular routes with an ID number.
I personally prefer to do it this way:
Put the following in your Post model (stick it at the bottom before the closing 'end' tag)
def to_param
permalink
end
def permalink
"#{id}-#{title.parameterize}"
end
That's it. You don't need to change any of the find_by methods. This gives you URL's of the form "123-title-of-post".
You can use the friendly_id gem. There are no special controller changes required. Simple add an attribute for example slug to your model..for more details check out the github repo of the gem.
The #63 and #117 episodes of railscasts might help you. Also check out the resources there.
You should have seolink or permalink attribute in pages' or posts' objects. Then you'd just use to_param method for your post or page model that would return that attribute.
to_param method is used in *_path methods when you pass them an object.
So if your post has title "foo bar" and seolink "baz-quux", you define a to_param method in model like this:
def to_param
seolink
end
Then when you do something like post_path(#post) you'll get the /posts/baz-quux or any other relevant url that you have configured in config/routes.rb file (my example applies to resourceful urls). In the show action of your controller you'll just have to find_by_seolink instead of find[_by_id].

Resources