I've used params in a URL for the index page successfully. But, I'm not getting the same success with the show page.
This is what I'm trying to use:
def show
#workorder = Workorder.find(params[:id])
#workorder = Workorders.where("wonum = #{params[:wonum]}") if params[:wonum].present?
Then I'm trying those URLs:
http://localhost:3000/workorders/?wonum='14-21291'
http://localhost:3000/workorder?wonum='14-21291'
Thanks for the help!
UPDATE 1
Rake Routes:
UPDATE2
What I would really like is this url to work:
http://localhost:3000/workorder?wonum='14-21263'
Could I add a route to the workorder show function?
You are almost there, you just need some minor changes and you'll get what you need.
It's important to understand that rails expects route ids to corrospond to database ids like the following:
http://localhost:3000/workorder/32'
This will save 32 in params[:id]
This is the default behavior and you will see this in all the rails beginner examples.
You will run into problems because you are trying to find Work orders by a different field, not id. So you need to change the code in your workorders controller.
Try this:
def show
#workorder = Workorders.where(:wonum, params[:wonum]).first if params[:wonum].present?
#workorder = Workorder.find(params[:id]) if #workorder.nil?
The major differences are how I call the where method (this way where add security for you) and trying to find a workorder from the :wonum parameter before trying to find it using the id. I suspect in your attempt, you were getting a record not found, or routing exception because you didn't pass in an id at all in your example url.
With an id:
http://localhost:3000/workorder?333wonum='14-21263'
I suggest looking at the sql generated in your rails server window to see what is going on.
You should look at this gem for a cleaner, off the shelf solution to what you're trying to do -> https://github.com/norman/friendly_id/
Related
I have tried using the Wicked gem 3 different times over the past 8 years. Each time, I have given up for the same reason. I'm trying again, because if I understand it, I think it will be perfect for my use case.
My main problem is that I don't understand how to actually begin the wizard. With the example used in the gem, it is an after_registration event that already has an associated user object. That is not helpful, nor do I think that example would be helpful in the majority of use cases.
There is another example about building a Product in multiple steps. However, the author fails to adequately explain the routing. From https://github.com/zombocom/wicked/wiki/Building-Partial-Objects-Step-by-Step:
Since Wicked uses our :id parameter we will need to have a route that also includes :product_id for instance /products/:product_id/build/:id. This is one way to generate that route:
resources :products do
resources :build, controller: 'products/build'
end
This also means to get to the create action we don't have a product_id yet so we can either create this object in another controller and redirect to the wizard, or we can use a route with a placeholder product_id such as [POST] /products/building/build in order to hit this create action.
OK, I have no idea what the second part of the sentence means as far as placeholder product_id and that route name of /products/building/build. I spent 2 hours trying that and just moved on to a blank create form.
...we can either create this object in another controller and redirect to the wizard
That's what I'm trying to do upon successful save of the #product object.
redirect_to product_by_interchange_path(#product, :step1)
That doesn't work. raise InvalidStepError if the_step.nil? Says my step is nil. It's not.
redirect_to product_by_interchange_path(#product, step: :step1)
Same thing.
redirect_to product_by_interchange_path(:step1)
That's an exact mirror of the 8 year old example app. But of course #product isn't in a session variable like current_user is, so in this case the error is that there's no Product with an id of :step1.
Please help! I am missing something very, very basic here but I very much need to persist.
OK I have finally figured this out. Here's what I did:
First of all, I changed my controller back to a plain old ApplicationController and used the include include Wicked::Wizard. I don't know if that did anything, but the newer example was laid out like the old.
I was really screwed up by :id. I'm thinking :id is generally my object ID. I had a set_product private method in my controller, and it was failing. When I finally figured out that :id was the actual step itself, that led me to change my path in the redirect.
I changed the redirect from product_by_interchange_path(#product, :select_vehicle) to product_by_interchange_path(:select_vehicle, product_id: #product.id)
I got rid of my set_product. Just while I was trying to eliminate confusion.
I changed my finder calls in the wizard to use :product_id instead of :id.
It works now. I still don't understand how I could have stubbed out a route with a placeholder product_id, that's still a mystery. But this is fine and it works.
The old sitemap of my application has already been indexed to Google now. For some one visiting my rails app with old url shouldn't go to 404.
The old url looked like this
/search?sub_category=210
Now after making them friendly, it looks like this:
/search?sub_category=milling-and-drilling.
I tried redirecting it from controller but it causes too much issues on other things. Such as filters which are using the same params. Is there a way I can do it from routes file?
Instead of using redirect_to route_path(id) you would do redirect_to route_path(object.find_by_id(id).name)
How to redirect old url to new url in rails using just routes?
AFAIK (As far as I know), no. (if through params)
The main job of routes.rb is to determine what "code" will handle the request, particularly that which matches request.url and the request.method. It does not concern yet of the request parameters nor its values: these would be handled in the controllers itself. Although, you can route based on parameters (or any information about the "request") through a routes constraint
Alternative Solution:
Instead of finding by ID, now find by "Slug name or ID".
In your models, particularly in this specific example of yours, add something like:
class SubCategory < ApplicationRecord
# if you're using a gem for the "friendly" urls, you don't need this method, and just use theirs.
def self.friendly_find!(friendly_id)
# this may not necessarily be `name`, maybe `slug`? or depending on your case
find_by(name: friendly_id) || find(friendly_id)
end
end
And in your controllers, just replace wherever you're finding a record (maybe also to other models not just SubCategory as needed be), particularly in your search action:
def search
sub_category = SubCategory.friendly_find!(params[:sub_category])
end
NOTE: friendly_find! will raise an Error if no record is found.
I've been racking my brain trying to figure out something that should be extremely simple, so I'm sure I'm just overlooking something and a fresh set of eyes might be useful since all my code is seemingly blurring together. I'm attempting to create vanity URLS for a site that allows users to create categories and then post relevant stories based on those categories. So, for example, I would like users to access /categories/movies in order to view the movie section. If I set it up to use the category id, /categories/1, it works no problem. For whatever reason, rails keeps trying to use the id parameter to find the category as opposed to the title parameter. I'm using Ruby 2.0.0 and Rails 4.0. I've read that the "find_by" method will become deprecated soon, so if there's a better way to handle this, that'd be great. Here's the relevant code:
Categories Controller
def show
#categories = Category.find_by_title(params[:title])
#category = Category.find_by_title(params[:title])
#posts = Post.where(category: set_category).all
end
Routes.rb
resources :categories
get "/categories/:title" => "categories#show"
Terminal readout when rendering page
Processing by CategoriesController#show as HTML
Parameters: {"id"=>"Movies"}
Just to reiterate, the parameters should read {"title"=>"Movies"} not id. Like I said, I'm sure it's something extremely simple that I've overlooked. Any help would be appreciated. Thanks.
I had to implement vanity urls as well and followed this blog post/tutorial
You pretty much create a slug in your model with the vanity-url, so
class Category < ActiveRecord::Base
def slug
title.downcase.gsub(" ", "-")
end
def to_param
"#{slug}"
end
end
Your show action in your controller would use the find_by_slug method
I think there is a gem that does this as well called friendly_id and here is a railscast but I have not personally used it
Hope this helps
How do I route to a page that ends with an id?
E.G.
before: site.com/messages/8
after: site.com/messages/terrytibbs
I've tried:
match "/messages/:username" => "messages#id"
No luck so far. Just trying to make the url have a little more meaning by replacing the number with the username of the user the current user is talking to.
Kind regards
If you want something simple without having to change your routes etc, why not do this:
class Message
def to_param
"#{id}-{username}"
end
...
end
Assuming you have a username attribute on your message. That will make your url look like:
site.com/messages/8-terrytibbs
this works because of the following (say in irb):
"8-terrytibbs".to_i
=> 8
and when rails looks up your message in your controller it will do the same thing to the id parameter.
EDIT: there is an excellent railscast on this here: http://railscasts.com/episodes/63-model-name-in-url and an updated version here: http://railscasts.com/episodes/63-model-name-in-url-revised
Take a look at friendly_id gem. I think it's what you need.
FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for Ruby on Rails. It allows you to create pretty URLs and work with human-friendly strings as if they were numeric ids for Active Record models.
Using FriendlyId, it's easy to make your application use URLs like:
http://example.com/states/washington
instead of:
http://example.com/states/4323454
Your route is set up correctly you have to change the Controller to use the correct parameters.
Assuming your MessagesController does:
def id
User.find(params[:id])
end
change to:
def id
User.find_by_username(params[:username])
end
I would also recommend adding indexing on user name.
You're on the right track, you just need to make sure the route is pointing at a proper action on the controller, like so:
Say the action you want this to point to is named show, here is how you would define the route:
match 'messages/:username' => 'messages#show'
Then if you navigate to messages/8, params[:username] will be set to '8' (parameters always come in as String's.
Likewise if you navigate to messages/terrytibbs, params[:username] will be set to 'terrytibbs'.
Try reading Chapter 3-3.5 of the Rails Routing Guide, it provides a good overview of how to bind parameters to a route like you are attempting to do.
So I am creating a ruby on rails application and in my view I have a list of link_to with each being a different console
In my database table I have a field called console.
What I want to do is when a user clicks on a link e.g. Playstation 3, it will return back all records that have Playstation 3 listed in that table column.
I was wondering how I would go about doing this, I have tried searching on the internet but have not found anything similar.
It is for a project that I don't have long to complete. I was owndering what I would state in the link to's in the view and what I would put in the games_controller.
Any help would be much appreciated.
The basic gist is to have a controller action which will return the list of games filtering by console. For example,
# GamesController.rb
def index
#games = Game.find_by_console(params[:console])
end
Then you can create a link for any particular console as such:
link_to 'XBOX', games_path(:console => 'XBOX')
This should result in a GET request to the URL /games?console=XBOX
If you've got a pre-defined set of consoles, you might look into making them into constants inside a Consoles module to avoid having to hardcode them everywhere.
UPDATE:
Since you are trying to implement both searching and filtering in the same chain, you need to make sure that find_by_console isn't called if it's not present.
# GamesController.rb
def index
#games = Game.search(params[:search])
#games = #games.find_by_console(params[:console]) unless params[:console].blank?
end