Ruby On Rails Updating Heroku Dynamic Routes
Fixed it!
There is something called an "ActiveRecord Observer" which have been depreciated since Rails 4.0. I found this website which explained what I wanted to do, but it was slightly outdated. I've included by code for rails 4.0 below:
If you're using Rails 4, use the rails-observers gem
Add the call to your environment files:
#config/application.rb (can be placed into dev or prod files if required)
config.active_record.observers = :slug_observer
Add a new observer class into your models folder:
#app/models/slug_observer.rb
class SlugObserver < ActiveRecord::Observer
def after_save(slug)
Rails.application.reload_routes!
slug.logger.info("Routes Reloaded")
end
def after_destroy(slug)
Rails.application.reload_routes!
slug.logger.info("Routes Reloaded")
end
end
The way this works is to call these bolt-on functions once the original has been run. This allowed my app to operate the function indepenent of the model in question, thus updating the routes correctly.
Is it a bad idea to reload routes dynamically in Rails?
Quick Solution
Have a catch-all route at the bottom of routes.rb. Implement any alias lookup logic you want in the action that route routes you to.
In my implementation, I have a table which maps defined URLs to a controller, action, and parameter hash. I just pluck them out of the database, then call the appropriate action and then try to render the default template for the action. If the action already rendered something, that throws a DoubleRenderError, which I catch and ignore.
You can extend this technique to be as complicated as you want, although as it gets more complicated it makes more sense to implement it by tweaking either your routes or the Rails default routing logic rather than by essentially reimplementing all the routing logic yourself.
If you don't find an alias, you can throw the 404 or 500 error as you deem appropriate.
Stuff to keep in mind:
Caching: Not knowing your URLs a priori can make page caching an absolute bear. Remember, it caches based on the URI supplied, NOT on the url_for (:action_you_actually_executed
). This means that if you alias
/foo_action/bar_method
to
/some-wonderful-alias
you'll get some-wonderful-alias.html living in your cache directory. And when you try to sweep foo's bar, you won't sweep that file unless you specify it explicitly.
Fault Tolerance: Check to make sure someone doesn't accidentally alias over an existing route. You can do this trivially by forcing all aliases into a "directory" which is known to not otherwise be routable (in which case, the alias being textually unique is enough to make sure they never collide), but that isn't a maximally desirable solution for a few of the applications I can think of of this.
Dynamic Rails routes based on database models
There is a nice solution to that problem using routes constraints.
Using routes constraints
As the rails routing guide suggests, you could define routes constraints in a way that they check if a path belongs to a language or a category.
# config/routes.rb
# ...
get ':language', to: 'top_voted#language', constraints: lambda { |request| Language.where(name: request[:language]).any? }
get ':category', to: 'top_voted#category', constraints: lambda { |request| Category.where(name: request[:category]).any? }
The order defines the priority. In the above example, if a language and a category have the same name, the language wins as its route is defined above the category route.
Using a Permalink model
If you want to make sure, all paths are uniqe, an easy way would be to define a Permalink
model and using a validation there.
Generate the database table: rails generate model Permalink path:string reference_type:string reference_id:integer && rails db:migrate
And define the validation in the model:
class Permalink < ApplicationRecord
belongs_to :reference, polymorphic: true
validates :path, presence: true, uniqueness: true
end
And associate it with the other object types:
class Language < ApplicationRecord
has_many :permalinks, as: :reference, dependent: :destroy
end
This also allows you to define several permalink paths for a record.
rails_category.permalinks.create path: 'rails'
rails_category.permalinks.create path: 'ruby-on-rails'
With this solution, the routes file has to look like this:
# config/routes.rb
# ...
get ':language', to: 'top_voted#language', constraints: lambda { |request| Permalink.where(reference_type: 'Language', path: request[:language]).any? }
get ':category', to: 'top_voted#category', constraints: lambda { |request| Permalink.where(reference_type: 'Category', path: request[:category]).any? }
And, as a side note for other users using the cancan gem and load_and_authorize_resource
in the controller: You have to load the record by permalink before calling load_and_authorize_resource
:
class Category < ApplicationRecord
before_action :find_resource_by_permalink, only: :show
load_and_authorize_resource
private
def find_resource_by_permalink
@category ||= Permalink.find_by(path: params[:category]).try(:reference)
end
end
rails 5 dynamic routing redirections based on model attributes
Found a solution on this post here.
I need to restart the server so newly created route get loaded after a Place object creation. Not sure if I am doing it right though but it works..
#config/route.rb
Rails.application.routes.draw do
Place.all.each do |pl|
get "/#{pl.shortlink}" => redirect("/users/sign_up?q=#{pl.id}&t=#{pl.token}")
end
end
In order to load the newly created route when adding a Place, I added
#models/place.rb
after_create :add_shortlink
...
def add_shortlink
Rails.application.reload_routes!
end
This will not work on Heroku, issue addressed is here
Dynamic segment in resourceful route
You can jump on to the console and type
$ rake routes
This will tell you the named routes for all of your possible routes. This particular route will not be in there as you have not named it. You need the :as
param
match '/confirm/:token' => 'users#confirm', :as => :confirm
Then the route will probably be (you can confirm with rake routes):
users_confirm_path(user_id, token)
Rails.application.routes.url_helpers crashing Heroku app
I had this same problem and found that is was caused due to 2 reasons:
First, using the Rails.application.routes.url_helpers methods in class constants like in the following snippet:
class myObject
include ActiveModel::Model
attr_accessor :id, :link
DEFAULT_OBJECT = new id: 1,
link: Rails.application.routes.url_helpers.my_object_url({:id => 1})
...
end
Second, setting config.eager_load = true
in the environment file.
So result being, when config.eager_load = true
, the dynamic url helpers haven't been registered when the myObject class is loaded.
This article maybe useful -> http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload/
Route all subdomains to my Heroku Rails app
In DNS setups, there are usually two parts to the equation: (1) the sending side, which is the DNS server that will direct the traffic to the server, and (2) the receiving side, which is the server being sent the traffic to, that often needs to know on which domains to listen.
The Heroku documentation on Wildcard domains is pretty clear:
Add a wildcard domain to your app as you would with any other domain, but use the
*
wildcard subdomain notation.$ heroku domains:add *.example.com
Adding *.example.com to example... done
The Heroku router is ready to receive your traffic. You just need to have your DNS point there. So, in your DNS—probably hosted at your registrar in your case—add your wildcard record:
*.example.com. CNAME example-1234.herokuapp.com
(or whatever Heroku tells you to put as CNAME)
Related Topics
Rails Form_For Never Invokes the Create Controller Action to Use Redirect_To
Tilt (Kramdown) Preventing Erb Processing When Rendering Markdown
Ruby, Value Bucketing, Beautify Code
Ruby: Sorting 2 Arrays Using Values from One of Them
Ruby: How to Remove Items from Array a If It's Not in Array B
Mongomapper Many to Many Issue with Array
Ruby Was-Sdk V2:Seahorse::Client::Networkingerror Exception: Ssl_Connect
Create and Initialize Instances of a Class with Sequential Names
Accessing Values Through Ajax Calls and Partials in Rails
Metasploit Induction of Bundle and Rake
Devise 'Find_First_By_Auth_Conditions' Method Explanation
Nomethoderror on Section 5.7 of Rails Guide
How to Marshal a Hash with Arrays
Vps Apache Config - Invalid Command 'Passengerdefaultruby' After Adding Latest Passenger Gem
Instantiate Capybara Browser and Set a Proxy
How to Convert a Large Gem to Standalone Rails App
Enter & Ioerror: Byte Oriented Read for Character Buffered Io
Rspec Error 'Report_Activate_Error': Could Not Find Rubygem Rspec-Core (>=0) (Gem:Loaderror)