I'd like to forward a bunch of stuff to a subdomain in my rails applications (including nested resources), without going through all my views to update all the link_to _path links. Is this possible?
EDIT
So far I have the following. Problem is, I can access everything either with or without the subdomain, without being redirect once I enter or leave a resource that should be on the subdomain. E.g. example.com/apps is the same as connect.example.com/apps, and the site root can either be example.com or connect.example.com
scope '/' do
with_options :conditions => {:subdomain => 'connect'} do |site|
site.resources :contracts
site.resources :bills
site.resources :feedbacks
site.resources :newsletters
site.resources :contacts
site.resources :apps do
site.resources :elements, controller: 'apps/elements' do
site.resources :features, except: [:index], controller: 'apps/elements/features' do
member do
site.post 'complete'
end
end
end
site.resources :comments, controller: 'comments'
site.resources :bills, controller: 'bills'
site.resources :contracts, controller: 'contracts'
end
end
end
EDIT 2
config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
r307 %r{/apps/(.*)}, 'http://connect.localhost:3000/apps/$1'
end
https://github.com/jtrupiano/rack-rewrite will let you do just this. It's web server agnostic so it won't matter that you're on heroku.
eg.
config.middleware.insert_before(Rack::Runtime, Rack::Rewrite) do
r307 %r{/apps/(.*)}, 'http://connect.example.com/apps/$1'
end
will issue a redirect for requests for /apps/ to go to connect.example.com/apps/
Related
so I have a route that is a bit more complex and I have an issue with the order of two nested scopes. Their order seems to be reversed. I want the most inner scope to be the last segment of the URL before the action. But it is the first.
routes.rb
namespace :customer do
namespace :api do
resources :products, only: [], param: :uid do
scope module: 'products' do
scope :buyer do
post :set_to_waiting_list, to: 'buyers#set_to_waiting_list'
end
end
end
end
end
Controller:
module Customer
module Api
module Products
class BuyersController < Customer::ApiController
def set_to_waiting_list
# do stuff
end
end
end
end
end
This gives me this route when running rake routes:
customer_api_product_set_to_waiting_list POST /customer/api/buyer/products/:product_uid/set_to_waiting_list(.:format) customer/api/products/buyers#set_to_waiting_list
But the URL I'm actually looking for is:
POST /customer/api/products/:product_uid/buyer/set_to_waiting_list
Reason is that this modifies the buyer and not the product. Also the buyer is fetched via the product uid (plus logged in user), so this URL format makes much more sense.
I don't really understand
I'm still interested in the logic behind this. But for anyone looking for an solution, I just solved it with:
namespace :customer do
namespace :api do
resources :products, only: [], param: :uid do
scope module: 'products' do
post :set_to_waiting_list, path: 'buyer/set_to_waiting_list' to: 'buyers#set_to_waiting_list'
end
end
end
end
You need to add a nested block so that the scope knows where to place the path prefix:
namespace :customer do
namespace :api do
scope module: 'products' do
resources :products, only: [], param: :uid do
nested do
scope :buyer do
post :set_to_waiting_list, to: 'buyers#set_to_waiting_list'
end
end
end
end
end
end
nested is not documented, so I'm not sure if you should rely on this. As an alternative, you can add a resource :buyers, only: [] {} wrapper:
namespace :customer do
namespace :api do
scope module: 'products' do
resources :products, only: [], param: :uid do
resource :buyer, only: [] do
collection do
post :set_to_waiting_list
end
end
end
end
end
end
The route and controller are the same in both cases, but the URL helper is different:
customer_api_product_set_to_waiting_list
POST /customer/api/products/:product_uid/buyer/set_to_waiting_list(.:format)
customer/api/products/buyers#set_to_waiting_list
vs
set_to_waiting_list_customer_api_product_buyer
POST /customer/api/products/:product_uid/buyer/set_to_waiting_list(.:format)
customer/api/products/buyers#set_to_waiting_list
Source: https://github.com/rails/rails/issues/12626
I need to define a method/action in my LessonsController that I can call from the lesson show action that marks the lesson as being completed by the current user. What does that controller method look like?
Here's the overview of my models:
User
has_many :completions
has_many :completed_steps, through: :completions, source: :lesson
Lesson
has_many :completions
has_many :completed_by, through: :completions, source: :user
Completions
belongs_to :user
belongs_to :lesson
My Completions Table looks like this:
t.integer "user_id"
t.integer "lesson_id"
t.boolean "completed_step"
t.string "completed_by"
I'm assuming in the LessonsController it looks like this
def complete_step
self.completions.create(completed_step: true, user_id: current_user.id)
end
Routes info:
Rails.application.routes.draw do
namespace :admin do
resources :users
resources :coupons
resources :lessons
resources :plans
resources :roles
resources :subscriptions
resources :completions
root to: "users#index"
end
devise_for :users, :controllers => { :registrations => "registrations"}
# Added by Koudoku.
mount Koudoku::Engine, at: 'koudoku'
scope module: 'koudoku' do
get 'pricing' => 'subscriptions#index', as: 'pricing'
end
resources :lessons do
member :complete
end
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'pages#home'
get '/dashboard' => 'pages#dashboard', :as => 'dashboard'
mount StripeEvent::Engine, at: '/stripe-events' # prov
end
Here's my button link to make this functional.
<%= button_to "Mark this Lesson as Complete", complete_lesson_path(#lesson), method: :put, class: "btn btn-warning btn-lg" %>
Will this work or am I WAY off? Thanks!
Keep this is the LessonsController, but change it in either of the following ways:
def complete_step
current_user.completions.create(completed_step: true, lesson_id: #lesson.id)
end
# ~~ OR ~~
def complete_step
#lesson.completions.create(completed_step: true, user_id: current_user.id)
end
Both of these assume that you've already set #lesson in the controller, probably in a before_action :set_lesson.
EDIT:
If you need a route suggestion, then assuming you have resources :lessons in your routes file, you can either use an existing route (likely update) or add a member route like this:
resources :lessons do
get 'complete', on: :member
end
If you add a route, then you will need to add an action that looks like
def complete
complete_step
redirect #lesson
end
or similar, however you want to handle the response itself. You will also need to ensure that #lesson is set, so you should tweak your before_action :set_lesson, only: [:show, :update, ...] to also include :complete
Please try with below code.in your completion controller
def create
#lession = Lession.find(params[:lession_id])
#completion = current_user.completions.create(completed_step: true, lesson_id: #lesson.id)
redirected_to #completion
end
You can also just pass user: current_user to the completions.create method instead of passing in the current_user.id
Something like #lesson.completions.create(completed_step: true, user: current_user)
I have this scope:
scope ":user_id", :as => "user" do
resources :boards, :controller => 'users/boards'
end
I get this route:
http://localhost/hyperrjas/boards/
I want a url without boards then on routes.rb I add:
scope ":user_id", :as => "user" do
resources :boards, :controller => 'users/boards', :path => '/'
end
That works great, but it is still accessible via "/boards" ... How do I prevent that? (I'm using Rails 3.1)
You shouldn't have to specify the controller names when using resources and in this caseI would use nested resources:
resource :user, only: :show do
resources :boards
end
This should give you the following:
/:user_id
/:user_id/boards
/:user_id/boards/new
/:user_id/boards/:id/
/:user_id/boards/:id/edit
and of course your restful routes!
Right now I have an admin.domain.com subdomain for which there is a module scope:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
end
end
This makes all requests on the admin subdomain hit controllers in app/controllers/admin/.
What I'd like to do now is something like:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
scope "history", :as => "history" do
resources :visitors
end
end
end
Where the end goal is to make admin.domain.com/history/visitors hit controller: app/controllers/admin/history/visitors_controller.rb.
This path however still looks for app/controllers/admin/visitors_controller.rb.
Any ideas?
namespace is what I was looking for:
constraints(AdminDomain) do
scope :module => "admin" do
resources :visitors
namespace :history do
resources :visitors
end
end
end
And I had to define Admin::History::VisitorsController in app/controllers/admin/history/visitors_controller.rb
easy way to define specific controller is just like:
:controller => admin/history/visitors
This is an excerpt from my config/routes.rb file:
resources :accounts do |account|
account.resource :profile, :except => [:new, :create, :destroy]
account.resources :posts,
:collection => { :fragment => :get },
:has_many => [:comments, :likes]
# even more code
end
I would like that each nested resource to be loaded from from the account namespace such as Account::PostsController instead of PostsController.
Using resources :accounts, :namespace => 'account' tries to load AccountPostsController.
Trying to nest the structure doesn't really work all that well:
map.namespace :account do |account|
..
end
The previous code will load the files from the locations I want, however it does add the namespace to the url and the generated paths so I'll have methods such as account_account_posts_url and similar paths.
Another alternative is to use something like:
account.resource :profile, :controller => 'account/profile'
I really don't like this as it involves both code duplication and forces me to remove some of the rails magic helpers.
Any thoughts and suggestions?
Changing my routes.rb and running rake routes I came up with the following:
map.resources :accounts do |accounts|
accounts.namespace :account do |account|
account.resource :profile, :except => [:new, :create, :destroy]
end
end
This gets you what you want. The correct url and pointing to account/... controller.
See Rails Routing for more detailed info and options on what can be done with Rails Routes.
So what's specifically wrong with namespacing? I think this is what you're trying to do:
map.namespace :account do |account|
account.resource :profile
end
This will try to load the controller at app/controllers/account/profiles_controller.rb and will generate routes such as account_profile_path.
Updated based on comment:
map.resources :accounts do |account|
account.resource :profile
end
Will give you /accounts/22/profile.