I'm trying to set up a simple edit feature for an object in one of my tables. Here is my current code which I've seen online and in books but it doesn't work
def edit
#fire_chief = FireChief.find(params[:id])
end
All I have to do is figure out how to edit a specific Fire Chief in list view and I can keep programming, but I'm stuck.
The error I'm recieving is "Couldn't find FireChief without an ID"
If I use this little snippet of code it finds the edit form fine
def edit
#fire_chief = FireChief.last
end
But it always pulls up the last entry to be edited. I need it to pull the entry that i click...might be the 1st, 3rd, or 5th, etc. I know a lot of this is redundant, but I just want to be clear on what I'm trying to do.
This is my routes file:
resource :timesheet do
resource :command_officer
resources :fire_chief
resources :fire_fighters
resource :safety_officer
resources :emts
resources :hazmat_specialists
resources :command_vehicles
resources :engines
resources :emergency_supports
resources :hazmat_units
resources :field_units
resources :pumpers
resources :tankers
resources :rescue_units
end
end
I just changed the resource :fire_chief to be plural, so now its this resources :fire_chief
But I'm getting this error now:
Routing Error
uninitialized constant FireChiefController
To get an id or any other data you need from params you have to pass the data inside the url like this example:
/firechief/2/edit
This way your edit method will know the id and the method will work. You can set this manually inside your routes, making a route like this:
get "/firechief/:firechief_id/edit" => "firechiefs#edit", as => :edit_firechief
Or if you are using resources inside your routes, it shall work by default.
If you actually does not want to pass any data inside your url, you could implement a session based solution. Create a method to store the id of the firechief inside a controller that fits your needs, or just add this line if you want to create the session inside a method (like firechief#create) you already has:
session[:firechief] = #here you add the id of the firechief you want to store
Now on your controller you can do this:
def edit
#fire_chief = FireChief.find(session[:firechief])
end
Related
I created a CRUD using the scaffold .
rails g scaffold intermediate_level/memory_game
And then I created the method Play, but when I call the method play an error is returned.
http://localhost:3000/intermediate_level/memory_game/play?id=1
Couldn't find IntermediateLevel::MemoryGame with 'id'=play
# Use callbacks to share common setup or constraints between actions.
def set_intermediate_level_memory_game
#intermediate_level_memory_game = IntermediateLevel::MemoryGame.find(params[:id])
end
def play {
#intermediate_level_memory_game = IntermediateLevel::MemoryGame.find(params[:id])
}
My routes.file
namespace :intermediate_level do
resources :memory_game
get 'memory_game/play'
end
Your custom get 'memory_game/play should come before resources :memory_game. Rails evaluates routes in the order in which they are listed in the routes.rb file, with the routes closest to the top of the file receiving the highest priority.
With your given routes information:
namespace :intermediate_level do
resources :memory_game
get 'memory_game/play'
end
You have these two routes:
GET /intermediate_level/memory_game/:id(.:format) intermediate_level/memory_game#show
and
GET /intermediate_level/memory_game/play(.:format) intermediate_level/memory_game#play
When you make this request:
http://localhost:3000/intermediate_level/memory_game/play?id=1
it is matched by both of those routes and as you defined: resources :memory_game before get 'memory_game/play' in your routes.rb file, so the first one (GET /intermediate_level/memory_game/:id) comes into action as that has higher priority, (because Routes have priority defined by the order of appearance of the routes in the config/routes.rb file) and then it tries to find the memory game with id param which in that case is play but fails to do so (as you don't have any memory game where id=play) and fails with the error message:
Couldn't find IntermediateLevel::MemoryGame with 'id'=play
One quick way to get around this issue is to reorder your routes like this:
namespace :intermediate_level do
get 'memory_game/play'
resources :memory_game
end
Then, your request url http://localhost:3000/intermediate_level/memory_game/play?id=1 will be served by GET /intermediate_level/memory_game/play(.:format) intermediate_level/memory_game#play route which is what you want.
I have a controller called CardController. Currently I have routes like card_path that map to /cards/:id. I would like to make it so that I can use /trips/:id and /events/:id that map to the same /cards/:id. I know I'll have to override card_path eventually but is it possible to set up my routes file for this? Do I need to set up a Trip and Event controller that just redirect to the card actions?
Edit:
Trips should completely map to cards, meaning 'trips/1/edit' should end up at 'cards/1/edit', 'trips/1/images/12' should end up at 'cards/1/images/12'
I ended up adding some controller to the routes file.
routes.rb
def card_routes
member do
get 'test'
end
end
class TripsController < CardsController; end
resources :trips { card_routes }
resources :cards { card_routes }
Now /trips/1/test and /cards/1/test go to the same place.
You can easily do something like:
get 'trips/:id' => 'cards#show'
Try accessing different trips in your browser, trips/1 or trips/2 (if cards with those ids exist), and they should redirect to the appropriate card.
If you haven't already, I recommend taking a few minutes and reading the Routing Guide, as it's really comprehensive and shows different ways of accomplishing things:
http://guides.rubyonrails.org/routing.html
I have a controller, clients_controller, with corresponding index, show, edit, delete, new & form views. Is there a way to create a new view like clients/prospects.html.erb that acts the same way as clients/index.html.erb, except is routed at clients/prospects/?
I've tried this:
match '/clients/prospects' => 'clients#prospects'
And some other things in routes.rb, but of course get the error "Couldn't find Client with id=prospects".
The goal here is basically to have a prospects view and a clients view, and by simply switching the hidden field to a 1, it (in the user's mind) turns a prospect into a client (it's a CRM-like app).
There's a couple of things you need to do. First you need to put the your custom route before any generic route. Otherwise Rails assumes the word "prospects" is an id for the show action. Example:
get '/clients/prospects' => 'clients#prospects' # or match for older Rails versions
resources :clients
Also you need to copy / paste the index method in your ClientsController and name it prospects. Example:
class ClientsController < ApplicationController
def index
#clients = Client.where(prospect: false)
end
def prospects
#prospects = Client.where(prospect: true)
end
end
Lastly, you need to copy the index.html.erb view and name the copy prospects.html.erb. In the example above you would have to work with the #prospects instance variable.
Create a new action in clients controller named prospects. And then define a collection route in routes.rb for it as either resource full way. Or u directly use match as you were doing.
What you're doing is not wrong (although I'd change match to get, otherwise POST and DELETE requests to that url will also render your prospects view). Presumably you have
resources :clients
in your routes file? If so, what you have will probably work if you just move the line you quoted above the resources declaration -- the problem is that /clients/prospects matches the show route for the clients resource, so if it's defined first then that's the route that gets matched.
However, there's a more idiomatic way to define this route
resources :clients do
collection do
get :prospects
end
end
See Rails Routing documentation for more
Also see migu's answer for what else needs to be done once the url is being routed correctly (though there are other things you can do -- if you the two views are similar enough, you can reuse the view template, for example).
I have the following routes in my config/routes.rb file:
resources :employees do
get 'dashboard'
get 'orientation'
end
employees refers to a regular resource handling the standard RESTful actions. dashboard and orientation are what I currently refer to "custom actions" which act on Employee instances. I apologize if I have my terminology mixed up and dashboard and orientation are really something else. These custom actions respond to URLs as follows:
http://myhost/employees/1/dashboard
i.e. They're "member" actions much like show, edit etc.
Anyway, this all works well enough. Regular actions such as show on EmployeesController obtain the ID of the associated Employee through params[:id]. However, with this current structure, dashboard and orientation have to use params[:employee_id] instead. This is not too difficult to deal with, but does lead to some additional code complexity as my regular before_filters which expect params[:id] don't work for these two actions.
How do I have the routing system populate params[:id] with the ID for these custom actions in the same way as show etc.? I've tried various approaches with member instead of get for these actions but haven't got anything to work the way I would like yet. This app is built using Ruby on Rails 3.2.
This might help you:
resources :employees do
member do
get 'dashboard'
get 'orientation'
end
end
and the above will generate routes like below, and then you will be able to use params[:id] in your EmployeesController.
dashboard_employee GET /employees/:id/dashboard(.:format) employees#dashboard
orientation_employee GET /employees/:id/orientation(.:format) employees#orientation
I haven't tested this example, but you can set the resourceful paths explicitly.
Something like this might work:
resources :employees, path: '/employees/:id' do
get 'dashboard', path: '/dashboard'
get 'orientation', path: '/orientation'
end
I am using ruby on rails to make a simple social networking site that includes different message boards for each committee of a student group. I want the url structure for each board to look like https://<base_url>/boards/<committee_name> and this will bring the user to the message board for that committee.
My routes.rb file looks like:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#index(name)'
My index function of committees_controller.rb file looks like:
def index(name)
#posts = Committee.where(name: name)
end
And then I'll use the #posts variable on the page to display all of the posts, but right now when I navigate to https://<base_url>/boards/<committee_name> I get an Unknown Action error, and it says The action 'index(name)' could not be found for CommitteesController.
Could someone guide me through what I have done wrong?
Once I get this working, how would I make a view that reflects this url structure?
Set up your routes like this:
resources :committees, only: [:index]
match '/boards/:name', to: 'committees#show'
and the controller like this:
def index
#committees = Committee.all
end
def show
#committee = Committee.find_by_name!(params[:name])
end
You can't really pass arguments to controller actions the way you were trying to with index(name). Instead, you use the params hash that Rails provides you. The :name part of the route declaration tells Rails to put whatever matches there into params[:name].
You also should be using separate actions for the listing of committees and displaying single committees. Going by Rails conventions, these should be the index and show actions, respectively.
When routing, you only specify the method name, not the arguments:
match '/boards/:name', to: 'committees#show'
Generally you will declare something with resources or match but not both. To stay REST-ful, this should be the show method. Index is a collection method, usually not taking any sort of record identifier.
Arguments always come in via the params structure:
def show
#posts = Committee.where(name: params[:name])
end
Controller methods that are exposed via routes do not take arguments. You may construct private methods that do take arguments for other purposes.