I have an application where it has beer, beercase, and drinker models on it. The beer inside the beercase can be assorted.
I'm bit struggling in how to show the information of a specific beer inside a beer case. Currently I listed all the beers inside the beercase of the drinker so I have a list of beer partial _beerlist:
<h1>beer you added</h1>
<% #drinker.beercase_line_items.each do |beer|%>
<p><%= link_to beer.beer.name, specificbeer_drinker_drinker_beercase_pages_path(#drinker) %></p>
<%end%>
I tried doing this but
<h1>beer you added</h1>
<% #drinker.beercase_line_items.each do |beer|%>
<p><%= link_to beer.beer.name, specificbeer_drinker_drinker_beercase_pages_path(#drinker,beer) %></p>
<%end%>
gives me a beer.20 at the middle of the URL, not beer/20 which I wanted for him to produce. Am I doing this right?
routes
resources :drinker do
resources :pages do
collection do
get :beercaselist # Name of beercase that can be added example:extrabucket-beercase
get :beercase # Show the beercase information and it has a link to add beer
end
end
resources :drinker_beercase # Controller to add what beercase that the drinker added
resources :drinker_beercase_pages do # Static page controller
collection do
get :beerlist # Show the beerlist
get :specificbeer # Show the specificbeer
end
end
resources :beercase_line_items # Controller to add what beer and what beercase
end
Okay, so bear with me, I don't think I fully understand your routes, but I think this may be your problem:
Your specificbeer_drinker_drinker_beercase_pages route looks like this:
/drinker/:drinker_id/drinker_beercase_pages/specificbeer(.:format)
That only has the :drinker_id parameter in it. This route is meant for displaying a list of specificbeers, not a single specific beer. If you change your routes file to look like this:
resources :drinker_beercase # controller to add what beercase that the drinker added
resources :drinker_beercase_pages do #static page controller
collection do
get :beerlist # show the beerlist
end
member do
get :specificbeer # show the specificbeer
end
end
end
Then the specificbeer_drinker_drinker_beercase_page will lead to this url:
/drinker/:drinker_id/drinker_beercase_pages/:id/specificbeer(.:format)
I'm not sure exactly if that's what you're going for, but hopefully it helps lead you in the right direction.
Related
I am creating a rails app whereby from a record's "show" page, the user is able to cycle through the record's nested resources (similar to a slideshow). For example, from the "show" page, the user will be able to link to the "show" for the first nested resource. From there, the user will be able to link to the "show" page of the next nested resource and so on. As the ids of each nested resource should be ordered smallest to largest, how can I create a link_to that looks for the next highest id (assuming nested resources are being created for multiple records simultaneously they may not necessarily be sequential) of a nested resource within a given record.
Because of Rails magic, you can pass the resource directly to the route helper, and it will use the correct id for that resource. For example:
<% #foo.bars.each do |bar| %>
<%= link_to bar.name, foo_bar_path(#foo, bar) %>
<% end %>
The above assumes that your route file looks something like:
resources :foos do
resources :bars
end
I highly recommend Rails Routing from the Outside In; it's been a very helpful resource for me!
To set the order of the child resource, you could use a scope, like this:
class Bar < ActiveRecord::Base
scope :ordered, -> { order(id: :asc) }
end
And then in your view, call foo.bars.ordered.each do |bar| etc.... Your nested resource will be returned from lowest to highest ID, skipping over any that have been deleted.
I hope this helps with what you were asking.
EDIT
I misread the question. To dynamically generate the "next" id, you could create method, next, on your child class. This answer seems to be something like what you want. Then in your view, you can just call:
<%= link_to "Next", bar_path(current_bar.next) %>
I have an app with shepherds (i.e. the users) and each shepherd has a set of animals. I am trying to make it so that if the logged in shepherd tries to view one of their animals it takes them to a view controlled by the edit action. Alternatively, if the shepherd tries to view another shepherd's animals it gives them a view controlled by the show action. I'd prefer to not have URLs with */edit - I want them to look the same for edit and show. In my routes.rb file I have this...
get '/shepherds/:username/:eartag', to: 'animals#show', as: :shepherd_animal_show
get '/shepherds/:username/:eartag', to: 'animals#edit', as: :shepherd_animal_edit
In the shepherd's show view I create a link to their animals like this...
<% if animal.shepherd == current_shepherd %>
<a href="<%= shepherd_animal_edit_path(username: animal.shepherd.username, eartag: animal.eartag) %>"
<% else %>
<a href="<%= shepherd_animal_show_path(username: animal.shepherd.username, eartag: animal.eartag) %>"
<% end %>
I can see that when I'm logged in and try to access my animals, it goes into the block with the shepherd_animal_edit_path, but it directs me to the show view rather than the edit view. Here's part of the output of the routes...
shepherd_animal_show GET /shepherds/:username/:eartag(.:format) animals#show
shepherd_animal_edit GET /shepherds/:username/:eartag(.:format) animals#edit
I'm a bit of a beginner at Rails and would really appreciate any help people can offer.
I think you should be using the show action for both, and just rendering a different template depending on the animal ownership. I.e.:
def show
...
render 'edit' if animal.shepherd == current_shepherd
# the show template will be rendered automatically if `render` wasn't explicitly called
end
Then in your view, you can unconditionally link to the show action, and the controller will take care of deciding which view template to render.
Also, FWIW, I would probably define the routes as follows:
resources :shepherds, shallow: true do
resources :animals
end
And then use the link_to helper in the view instead of hard-coding HTML tags:
<%= link_to animal_path(animal) %>
But that would then allow you to do other things like:
link_to shepherd_animals_path(#shepherd) # link to the `index` action of `AnimalsController`, with `params[:shepherd_id]` set to `#shepherd.id`.
That would then allow you to render (or not render) other controls for the shepherd to manage his/her own flock if current_shepherd.id == params[:shepherd_id] (or current_shepherd == Shepherd.find(params[:shepherd_id])).
I made a scaffold named b_page and I created a migration for bio I added a biopage.html.erb
In controller:
def biopage
#b_pages = BPage.all
end
in routes.rb
resources :b_pages do
collection do
get 'biopage'
end
end
in bio.html.erb:
<div class="jumbotron">
<h1>Bio of :</h1>
<h2><b><%= #b_page.Bpage_name %></b></h2>
<h3><%= #b_page.user.email %></h3>
</div>
<%= #b_page.bio %>
but i still get the error:
ActiveRecord::RecordNotFound in BPagesController#show
Couldn't find BPage with 'id'=biopage
highlighting:
#b_page = BPage.find(params[:id])
First of all, this seems a bit odd to me:
resources :b_pages do
collection do
get 'biopage'
end
end
as it will result in a route like: /b_pages/biopage. You might want to just do something like:
resources :b_pages, except: :show
get '/biopage/:id', to: 'b_pages#show'
This way, your biopage route will go to the show controller method and you will still have the other b_pages routes to work with.
You are seeing the ActiveRecord::RecordNotFound error message because you have no BPage object to show, so the show method is complaining. Notice how the route I wrote above uses :id - this is because the show action normally takes an id of some record to display on the front end. If you want to use biopage and link it to the show method, you should be returning an object to actually show. Otherwise you should probably create a completely different controller method for biopage that does not interfere with the b_pages resources. Something like this in the routes:
resources :b_pages
get '/biopage/:id', to: 'b_pages#your_method'
and in the controller you'd have
class BPages < ApplicationController
# index, show, destroy, etc. here
def your_method
# Get whatever object you want returned here
end
end
I have a payments table. In the index view I list all payments in a table and in the show view I'd like to show a form of all payments where a user can select which ones to further process.
Above the table in the index action view I have:
<%= link to "Customise", show_payment_path %>
Then in the controller:
def show
#payments = Payment.all
end
In my routes file:
resources :payments
The error I am getting is:
undefined local variable or method `show_payment_path'
I have tried
<%= link_to 'Customise Sepa Mandate', show_payments_path %>
as well but that gives the same error. As does using url instead of path.
The path for resourceful-routed show actions is just payment_path (singular resource) or payment_path(id). Your “customize” link would lead me to believe you actually want edit_payment_path(id), though.
See Rails Guides — Generating Paths and URLs From Code for more info.
Run rake routes command to see available routes and correct syntax.
Pass show_payment_path(:id) to get the particular payment show page.
for that make your own routes and create their own path variable such as
resources :payments, except: [:show] do
get '/show' => "payments#show", on: collection, as: :show
end
What is your solution to the problem if you have a model that is both not-nested and nested, such as products:
a "Product" can belong_to say an "Event", and a Product can also just be independent.
This means I can have routes like this:
map.resources :products # /products
map.resources :events do |event|
event.resources :products # /events/1/products
end
How do you handle that in your views properly?
Note: this is for an admin panel. I want to be able to have a "Create Event" page, with a side panel for creating tickets (Product), forms, and checking who's rsvp'd. So you'd click on the "Event Tickets" side panel button, and it'd take you to /events/my-new-event/tickets. But there's also a root "Products" tab for the admin panel, which could list tickets and other random products. The 'tickets' and 'products' views look 90% the same, but the tickets will have some info about the event it belongs to.
It seems like I'd have to have views like this:
products/index.haml
products/show.haml
events/products/index.haml
events/products/show.haml
But that doesn't seem DRY. Or I could have conditionals checking to see if the product had an Event (#product.event.nil?), but then the views would be hard to understand.
How do you deal with these situations?
Thanks so much.
I recommend you to make separate admin controller with it's own views to administrate everything you want. And your customer's logic stayed in products contoller.
I don't have good and clean solution for this problem. Usualy if views doesn't differ to much, I use single view and add some code like #product.event.nil?. You can always add some variable, or helper that will make this method shorter, on example has_event? - then your view will look cleaner. And use it in code like this:
<% if has_event? %>
some html
<% end %>
or for single line:
<%= link_to 'Something special', foo_path if has_event? %>
On the other side, you can create few partials that are the same for both views, put them in some folder, on example /shared/products/... and render them from your views like this:
<%= render :partial => '/shared/products/info' %>
and so on.
But if they don't differ too much, I really would use if version.
The views will be handled by the ProductsController. You can alter the logic in your controller depending on the nesting of the resource.
# app/controller/products_controller.rb
# ...some code...
def index
#event = Event.find_by_id(params[:event_id]) if params[:event_id]
#products = #event ? #event.products : Product.all
end
The view will be handled by the usual product view
# app/views/products/index.html.haml
- unless #products.blank?
- #products.each do |product|
%p= product.some_attribute