Accessing a Module Resource with Rails 4.x - ruby-on-rails

I am using rails 4.1 with Casein CMS: https://github.com/russellquinn/casein
I have setup a Post Model, view and controllers within casein, but I would like to access the Posts outside of casein, possibly under another route called blog
I have tried and tried reworking my routes and controllers, and have an array of errors to list. Someone here might know just the trick to get this working, and was hoping some could help me, or at least explain to me what should be happening or what I might be doing wrong.
What Casein adds to the routes is this:
#Casein routes
namespace :casein do
resources :posts
end
And I'd like to match the index and show actions to => /blog. How might I write this correctly in my routes.rb.
My controller, I have basically extracted the actions from the Casein's PostsController, and along with including the Casein Module have tried to simple list all the posts.
Here is what my blogs_controller's index action looks like:
class BlogsController < ApplicationController
module Casein
def index
#casein_page_title = 'Posts'
#posts = Post.order(sort_order(:title)).paginate :page => params[:page]
end
end
end
By the end I'd also like to take blogs to blog, but I think can take it from there, but if anyone has any suggestions, that would be much appreciated.

You might be asking for this, but your question is not very clear.
If you want to have the following routes and use the same controller for each.
Prefix Verb URI Pattern Controller#Action
casein_posts GET /casein/posts(.:format) casein/posts#index
POST /casein/posts(.:format) casein/posts#create
new_casein_post GET /casein/posts/new(.:format) casein/posts#new
edit_casein_post GET /casein/posts/:id/edit(.:format) casein/posts#edit
casein_post GET /casein/posts/:id(.:format) casein/posts#show
PATCH /casein/posts/:id(.:format) casein/posts#update
PUT /casein/posts/:id(.:format) casein/posts#update
DELETE /casein/posts/:id(.:format) casein/posts#destroy
blog GET /blog(.:format) casein/posts#index
GET /blog/:id(.:format) casein/posts#show
then your config/routes.rb file should contain
namespace :casein do
resources :posts
end
get '/blog', to: 'casein/posts#index'
get '/blog/:id', to: 'casein/posts#show'
And you need your controller to be app/controllers/casein/posts_controller.rb
But I'd really strongly encourage you to use 2 different controllers, and a concern for the shared methods

Related

Rails getting routes name in Route.rb with controller actions

I'm a real beginner of rails.
Can I get multiple routes from one controller + many actions?
For example,
resources :something
get "something#index", "something#show", "something#update"...etc.
I'm just curious if there is a command to get route name from the actions.
For example, in a controller named "pledges",
class PledgesController < ApplicationController
def home
end
def abc
end
def defg
end
def hijk
end
end
Can any commands get "pledges#home", "pledges#abc", "pledges#defg","pledges#hijk" ?
To add custom, "non-RESTful" routes to a resource, you could do the following:
resources :pledges do
collection do
get :foo
end
member do
put :bar
end
end
collection-defined routes will produce results against Pledge as a whole – think the index route.
member-defined routes will produce results against an instance of Pledge – think the show route.
This would produce the following routes for you:
foo_pledges GET /pledges/foo(.:format pledges#foo
bar_pledge PUT /pledges/:id/bar(.:format) pledges#bar
pledges GET /pledges(.:format) pledges#index
POST /pledges(.:format) pledges#create
new_pledge GET /pledges/new(.:format) pledges#new
edit_pledge GET /pledges/:id/edit(.:format) pledges#edit
pledge GET /pledges/:id(.:format) pledges#show
PATCH /pledges/:id(.:format) pledges#update
PUT /pledges/:id(.:format) pledges#update
DELETE /pledges/:id(.:format) pledges#destroy
You will have to define all of the custom actions, if there are not restful (but I would highly recommend that you follow the rest conventions). For example:
get 'pledges' => 'abc'
post 'pledges' => 'defg'
put 'pledges' => 'hijk

Rails - using namespace controllers to organize files

I am trying to learn about namespacing.
I've asked a few questions on this topic previously, but I'm not understanding what is going on.
I have made a folder in my controller's folder called 'features'. In it, I have saved a file called app_roles_controller.rb.
The first line of that controller is:
class Features::AppRolesController < ApplicationController
The purpose of the features folder is so I can organise my files better (that's it).
In my routes.rb, I have tried:
resources :app_roles, :namespace => "features", :controller => "app_roles"
I have also tried:
namespace :features do
resources :app_roles
end
I have a model (top level) called app_role.rb and I have a views folder saved as views/features/app_roles which then has the index, show etc files in it. The table in my schema is called 'app_roles".
When I rake routes for app_roles, I get:
Paths Containing (app_role):
app_roles_path GET /app_roles(.:format)
app_roles#index {:namespace=>"features"}
POST /app_roles(.:format)
app_roles#create {:namespace=>"features"}
new_app_role_path GET /app_roles/new(.:format)
app_roles#new {:namespace=>"features"}
edit_app_role_path GET /app_roles/:id/edit(.:format)
app_roles#edit {:namespace=>"features"}
app_role_path GET /app_roles/:id(.:format)
app_roles#show {:namespace=>"features"}
PATCH /app_roles/:id(.:format)
app_roles#update {:namespace=>"features"}
PUT /app_roles/:id(.:format)
app_roles#update {:namespace=>"features"}
DELETE /app_roles/:id(.:format)
app_roles#destroy {:namespace=>"features"}
I can't understand what it is that I'm doing wrong.
When I try:
http://localhost:3000/app_roles#index
I get an error that says:
uninitialized constant AppRolesController
When I try:
http://localhost:3000/features/app_roles#index
I get an error that says:
No route matches [GET] "/features/app_roles"
I'm looking for a plain English explanation of how to set this up. I've tried the programming ruby book (several times over).
Please, can you help me understand what needs to happen to introduce organisational files in my rails app?
It looks like your other attempt was actually correct. As outlined in the Rails documentation, if you want to generate routes for the resource app_roles under the namespace features you can add the following to your routes.rb file:
namespace :features do
resources :app_roles
end
Now, you run rake routes you will see the following:
Prefix Verb URI Pattern Controller#Action
features_app_roles GET /features/app_roles(.:format) features/app_roles#index
POST /features/app_roles(.:format) features/app_roles#create
new_features_app_role GET /features/app_roles/new(.:format) features/app_roles#new
edit_features_app_role GET /features/app_roles/:id/edit(.:format) features/app_roles#edit
features_app_role GET /features/app_roles/:id(.:format) features/app_roles#show
PATCH /features/app_roles/:id(.:format) features/app_roles#update
PUT /features/app_roles/:id(.:format) features/app_roles#update
DELETE /features/app_roles/:id(.:format) features/app_roles#destroy
The first line for example means that if you make a GET request to /features/app_roles it will be routed to the index action in the features/app_roles controller.
In other words, if you visit http://localhost:3000/features/app_roles it will route the request to index action that is located in app/controllers/features/app_roles_controller.rb which it expects to have the class Features::AppRolesController.
So your app/controllers/features/app_roles_controller.rb file should look something like this:
class Features::AppRolesController < ApplicationController
def index
end
end

Rails routing: Scope using a database field

I am creating an multitenant app based on ideas from Ryan Bigg's book "Multitenancy with Rails". In this book, the tenants has their own subdomain. This approach is not applicable in my case, so I'm trying to scope by a slug of the account's name instead.
So instead of URLs like http://account-name.myapp.com, i want http://myapp.mydomain.com/account-name/. The subdomain is reserved for the app itself, because I want to be able to have more than one app on my domain.
Here's a piece of my routes.rb:
scope module: 'accounts' do
resources :customers do
resources :notes
end
end
To achieve my goal, i try to follow the routing guide on rubyonrails.com (the last code snippet in chapter 4.5), and change the above code to:
scope ':slug', module: 'accounts' do
resources :customers do
resources :notes
end
end
slug is an attribute in the accounts table in the database, so if an account is called "My Business", the slug will typically be "my-business".
This change seems to correct my routes:
customers GET /:slug/customers(.:format)
.. but it also seems to break my site, as the slug is not fetched from the database. I can't seem to wrap my mind around how this scope':slug', module: 'accounts' works. Is Rails supposed to automatically recognize :slug as an attribute of the Accoounts table? If not, can anyone please help me find a way to use the account's slug in my URLs?
I have googled around for a couple of days now, and read numerous answers here on Stackoverflow. Nothing helped, so any pointers is greatly appreciated. :-)
EDIT:
The relevant controllers are set up like this:
controllers/accounts/base_controller.rb
controllers/accounts/customers_controller.rb
controllers/accounts/products_controlelr.rb
controllers/accounts_controller.rb
controllers/application_controller.rb
The accounts_controller.rb only has actions for new and create at this point.
The accounts/base_controller.rb look like this:
module Accounts
class BaseController < ApplicationController
before_action :authorize_user!
def current_account
#current_account ||= Account.find_by_slug(params[:slug])
end
...
end
end
I addded this to my Account model:
def to_param
slug
end
Before i tried to implement scope ':slug' in my routes, everyting worked when logged in users where directed to myapp.mydomain.com/dashboard and navigated to i.e. myapp.mydomain.com/customers. Now it works with myapp.mydomain.com/account-name/dashboard, but as soon as I try to navigate to a view that use helpers like new_customer_path, i get the error:
No route matches {:action=>"show", :controller=>"accounts/customers", :id=>nil, :slug=>#
I hope this makes my issue clearer. :-)
I am not sure whether your routes is set up correctly or not because you didn't post your controller source code, but basically how it works if very simple. If you are using the current routes you set up what you should do is create an account_customers_controller.rb file in controllers\account\folder, and it should look like this:
class Accounts::CustomersController < ActionController::Base
def show
#account = Account.find_by_slug(params[:slug])
...
end
end

Obtaining ID of containing resource via params[:id] for custom actions

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

Rails route parent ID name and CanCan issue

I'm trying to get a simple route working
/agenda_items/5/feed
To do this, I have the following route setup
resources :agenda_items do
member do
get "/feed", to: "comments#feed"
end
end
In each of my controllers, I'm using CanCan to handle the authentication and it works fine, however on this one action I'm having an issue, which I'm pretty sure is down to railsnaming generation. When I runrake routes`, the route above is produced as
feed_agenda_item /agenda_items/:id/feed(.:format) agenda_items/:id#feed
As far as I can tell, CanCan is expecting the :id parameter, to actually be :agenda_item_id so as a result, my parent resource isn't being loaded.
Is there any way I can get rails to change this so that CanCan will work without me having to manually load and authorize the resource, or is there a way I can get CanCan to change what it's looking for on certain actions?
The problem is that your routes are wrong. You try to create a member action for agenda items which routes to the comments controller. If you want a feed of all the commments from a single agenda item you should do something like this:
resources :agenda_items do
resources :comments do
collection do
get :feed
end
end
end
You should now get the following when running rake routes:
feed_agenda_item_comments /agenda_items/:agenda_item_id/feed(.:format) comments#feed

Resources