Rails Nested Resource Scoped to Controller - ruby-on-rails

In my app, websites have many pages. I'm trying to setup my URLs to look like
example.com/websites/1/pagename
I want it so page names don't need to be globally unique. They just need to be unique within the website they belong to.
This is what my routes look like so far
resources :websites do
resources :pages, :path => ''
end
UPDATE
I got it working by changing this line in the pages controller.
def show
#page = Page.find_by(website_id: params[:website_id], id: params[:id])
end
However, then I updated that line to use Friendly ID...
def show
#page = Page.friendly.find_by(website_id: params[:website_id], id: params[:id])
end
Now I get an error undefined method name for nil:NilClass because I have <% provide(:title, #page.name) %>

No, You don't need.
The rails g controller websites/pages to use with namespace.
Your URL: websites/1 the id = 1 is unique. and the pagename also unique for each website
=> websites/1/pagename is unique
It's fine for:
websites/1/page_about_author
and
websites/2/page_about_author

Related

Ruby On Rails adding new page after scaffolding

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

Rails 4 Routing - undefined local variable

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

Dynamic routes on runtime in Rails

I'm developing a site using refinery. Now for one specific page that is created in the back-end of refinery, i want to use my own controller and views. All the User can do with this page is to set the menu-position, title, meta-info etc. The URL for this page has to look the same as all the other pages.
So for example, the menu structure looks like:
menux
menu1
menu2
specific page
menux
And the URL for "specific page" looks like "locale/menu1/menu2/specific page"
The site is available in multiple languages, so i have to create these routes for all languages.
Currently i'm creating the routes like this:
specific_page_id = 1
Refinery::I18n.frontend_locales.each do |lang|
slugs = []
page = Refinery::Page.find_by_path_or_id(nil, specific_page_id)
# get slug for page in current language
slugs << page.translations.select { |p| p.locale == lang }.first.slug
# get all slugs from parrent pages
while !page.parent_id.blank?
page = Refinery::Page.find_by_path_or_id(nil, page.parent_id)
slugs << page.translations.select { |p| p.locale == lang }.first.slug
end
match "/:locale/#{slugs.reverse.join("/")}" => "controller#action", :via => :get, :constraints => { :locale => /#{lang}/ }
end
With this, i'm getting a route to the specified page in every language like described above.
But the problem is, when the user changes the name of the page or the position in the menu, the routes have to be generated again, which isn't done too often.
Now my question is, how can i do this more dynamically on run-time? I've read a bit about constraints but i don't know if this is what i need.
Thanks for your help!
I needed to figure out building routes off a database model myself in a Rails 4 application (which is called "ComingSoon" in the examples below. I wanted pages that could be edited on the back-end and given a user-friendly name, which is stored in the Page#name field. So "About Us" titled page typically becomes "about_us" name, which leads to "http://localhost:3000/about_us" The following is the technique I came up with:
Create a new model in app/models/dynamic_router.rb
class DynamicRouter
def self.load
ComingSoon::Application.routes.draw do
Page.all.each do |pg|
get "/#{pg.name}", :to => "pages#show", defaults: { id: pg.id }, as: "pages_#{pg.name}"
end
end
end
def self.reload
ComingSoon::Application.routes_reloader.reload!
end
end
The key above is that I pass the page's id as one of the parameters, so look up is still on the Page#id field, which is, IMHO, a lot better than using the friendly plugin or lookups on slugerized values.
Add the following line to your config/routes.rb
ComingSoon::Application.routes.draw do
# ...
DynamicRouter.load
end
Finally, when the Page is updated, we need to reload the routes, so add an after_safe callback on the Page model:
class Page < ActiveRecord::Base
after_save :reload_routes
def reload_routes
DynamicRouter.reload
end
end
I plan to refine this further to only reload routes if the name attribute is changed and perhaps simply edit the existing route rather than reloading everything if performance proves to be an issue (which at the moment, its not).

Rails will_paginate - how to make nicer route?

I have on the homepage list of articles that are listed with using will_paginate gem.
Everything works well, but there is one thing I would want to improve - on the homepage, the data are loaded into home controller and index action.
So, when I load my website - www.website.com, data are loaded into home/index. When I click on the pagination link for the second page, the link is www.website.com/home/index?page=2. I would like to see there in the best way www.website.com/page/2 (or www.website.com/?page=2).
Basically, the point is to remove from the URL /home/index - is there any way to do this?
Thanks
You may do it this way - add this class to some helper module, for example app/helpers/application_helper.rb:
module ApplicationHelper
class SmartLinkRenderer < WillPaginate::ActionView::LinkRenderer
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
attributes[:href] = target.gsub(/[?&]page=(\d+)/,'/page/\1')
tag(:a, text, attributes)
end
end
end
You may customize it according to your needs, for example do
attributes[:href] = target.gsub(/home\/index/,'')
or whatever. And then you may do this in your views:
<%= will_paginate #items, :renderer => 'ApplicationHelper::SmartLinkRenderer' %>
Try this
root to: 'home#index'
in you config/routes.rb file
EDIT
to be able to route these kind of requests:
www.website.com/page/2
add this to routes.rb:
match "page/:page" => "your_root_controller#index"
this way :page will be in your params hash.
and for example index method to view your Message model can be:
def index
#messages = Messages.paginate(page: params[:page])
end
hope that can help. for more information please refer to RoR routing

How do I create a rails controller action?

My rails app has a single CustomerSelectionController, with two actions:
index: which shows a form where the user can enter customer information and
select: which just displays a static page.
class CustomerSelectionController < ApplicationController
def index
end
def select
end
end
I've created an entry in my routes.rb file:
resources :customer_selection
and the form in the index view looks like:
<h1>Customer Selection</h1>
<%= form_tag("customer_selection/select", :method => "get") do %>
<%= submit_tag("Select") %>
<% end %>
however when I click on the Select button in the browser, all I get is:
Unknown action
The action 'show' could not be found for CustomerSelectionController
I'm not sure why it is trying to perform an action called show? I haven't defined or referenced one anywhere.
I'm not sure why it is trying to perform an action called show? I haven't defined or referenced one anywhere.
Yes you have. That's what resources does. It defines the seven default RESTful routes: index, show, new, create, edit, update and destroy. When you route to /customer_selection/select, the route that matches is "/customer_action/:id", or the "show" route. Rails instantiates your controller and attempts to invoke the "show" action on it, passing in an ID of "select".
If you want to add a route in addition to those, you need to explicitly define it, and you should also explicitly state which routes you want if you don't want all seven:
resources :customer_selection, only: %w(index) do
collection { get :select }
# or
# get :select, on: :collection
end
Since you have so few routes, you can also just define them without using resources:
get "/customer_selection" => "customer_selection#index"
get "/customer_select/select"
Note that, in the second route, the "customer_select#select" is implied. In a route with only two segments, Rails will default to "/:controller/:action" if you don't specify a controller/action.

Resources