So we use the same controllers to serve both mobile and desktop views of our site. We also use action caching heavily to cache the html for a page in memcache. I've been trying to figure out a way to globally change the caching prefix for all mobile requests to "views-mobile/" instead of the standard "views/". That way the mobile and and desktop pages will be saved under a different namespace so there are no conflicts in memcache.
We could do this per caches_action method by creating a custom cache_path using the controller variable for is_mobile?, but we'd prefer to do it globally somehow. Any suggestions? I imagine this would require monkey-patching ActionController::Caching but I can't figure out where it generates the "views/" prefix.
I'm sorry, I was Rails nubie, so I don't really understand about your question, but if it right, is this what you mean?
This is on my routes.rb:
scope "/administrator" do
resources :users
end
I changed my users_path 'prefix' to administrator. Sorry if wrong :D
I actually ended up figuring this out myself. Basically ActionController::Base uses a function called fragment_cache_key to generate the cache key for a specific fragment (which is what ActionCaching uses deep down). So you basically override that method and include your own logic for how to generate the prefix. This is how my method override looks:
# Monkey patch fragment_cache_key
def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, mobile_device? ? "views-mobile" : "views")
end
Where mobile_device? is my own function that figures out whether the user is requesting the mobile or desktop version of the site.
Related
We are in the process of taking a few pages out of our rails app to be served separately (they are a few static pages with some content being managed through a cms). The urls will stay the same. Our own routing system in front of the servers will decide which request should go to the rails app and which to the static part.
My question is about path helpers that we use quite a bit throughout the rails app, such as link_to about_path that generate mahwebsite.com/about. As I understand I can just leave them be, they will still generate correct urls. My only concern is that for them to work I'll have to keep the routings in the routes file, which will have to be connected to the dummy controller methods. Seems like a lot of redundant code just to fool rails into creating path helpers.
Alternatively, I can hard-code links to the static pages. But before I start replacing a whole lot of code, I'd like to know if there is a clean Railsy way to keep the path helpers without having to route to the redundant controllers.
Thanks.
Why not just create your own helper method? E.G.
# application_controller.rb
def about_path
"mahwebsite.com/about"
end
helper_method :about_path
alias_method :about_url, :about_path
This will overwrite any Rails helper method and do exactly what you're after :)
Hope this helps - give me a shout if you've any questions or comments.
How about
resources :custom_pages, only: [:your_options] do
get :view/:page_id_or_whatever_for_identify
end
and do the following content with the controller?
I'm doing an API with grape gem, in one of my services I would like to retrieve the complete URL. For example if the user does request on :
api.myapp.com/android/users.json
I would like be able to retrieve api.myapp.com/android/users.json or at least /android/users.json
class MyApp::API::Users < Grape::API
resource :users do
get do
request.original_url
# stuff ...
end
end
end
I tried what I know from Rails, but now it's Grape and it doesn't work :
"error": "undefined method `original_url' for #<Grape::Request:0x00000005a78c08>"
I wanted to do the same thing (generate absolute URIs) within my own API and after much research, I eventually gave up. There is, amazingly, no good way I can find to get the information you're looking for out of Grape—you cannot, for instance, specify a resource is "mounted" at a specific path and then retrieve that information later.
What I wound up doing in the meantime was saving the base URL (scheme, hostname and port) in a global variable at the start of each request:
before do
# Save the base URL of the request, used by resources to build
# their canonical URI
Resources::base_url = request.base_url
end
and then, within each resource representer, "manually" assembling the URI using hardcoded path information:
link :self do
RideYork::API::Resources::base_url +
"/resources/agencies/#{represented.id}" if represented.id
end
It's a terrible hack, but I'm not aware of a better solution.
Grape::Request is just a Rack::Request. It looks like the Rack::Request has a #url method you could try.
I have an engine (developed by me / the company I work for) that we use on several different projects. I just converted it to work with rails 3.1 w/ assets pipeline and everything seems to be working... for the most part.
My problem is that I need to extend the functionality of the UsersController with a little bit of app-specific spice, but I'm not sure about the best way to do it. The engine doesn't define a Users#show action, but this app does need it, so I added to the routes file:
JobEngine::Application.routes.draw do
root :to => 'home#index'
resource :users, :only => [:show]
resources :jobs, :only => [:show]
end
Then in my application I created the UsersController:
class UsersController < MyEngine::UsersController
def show
end
end
Then I made a users/show.html.haml view, I've stripped it down to only show one of the problem lines:
= link_to "Somewhere", job_path(3)
This gives me an error that reads undefined method 'job_path' for #<#<Class:0x00000102d69900>:0x00000102d4ed30>
Which is bizarre because before I made my app's UsersController inherit from MyEngine::UsersController it worked just fine.
When I do rake routes in the console, there are these lines:
users GET /users(.:format) {:action=>"show", :controller=>"users"}
job GET /jobs/:id(.:format) {:action=>"show", :controller=>"jobs"}
I can alter the class definition to be:
class UsersController < ApplicationController
and then the link works just fine. However, the engine's controller MyEngine::UsersController already inherits from ApplicationController. I can put code into my app's ApplicationController (like a before_filter) and it will run as expected, so I know my class definition does ultimately hit my app's ApplicationController, why is the job_path helper not working?
When I change the show action to read:
def show
job_path(3)
end
I get the error:
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"jobs", :id=>3}):
app/controllers/users_controller.rb:9:in `show'
Which further confuses me because now it actually does recognize job_path as a method, but somehow the router isn't picking up where to go with all the correct parameters.
What am I doing wrong? What is the correct way to extend engine controller functionality? I saw the extending engine functionality question here.
And followed that code example, changing my class definition to instead re-open MyEngine::UsersController but I still get the exact same results concerning job_path(NUMBER)
UPDATE:
Ok I sort of figured out what's going on. Let's say your engine has a job_path route, and your application has a job_path route. If you're on a page that was accessed via an engine's controller, you can call the engine's helper with just job_path, but you can also call the main application's helper with main_app.job_path.
Likewise, if you're on a page accessed via one of your application's controllers, you access the engine's helper with my_engine.job_path and your own application's helper with job_path. This is assuming that you have something like mount MyEngine::Engine => "/my_engine", :as => 'my_engine'.
When you inherit an engine controller from your application, it then completely changes your route helpers to think you're in the context of the engine through the controller/view lifecycle. So to fix my problem all I really have to do is change it to be main_app.job_path(3) and it works.
I'm not completely satisfied with this solution because it feels a little...weird. Maybe I have a partial on this page that will be used on a separate non-inheriting page. Now the link helper will only work for one of the two pages, but never both =\ Am I missing something here...?
Try changing your Mount path in main app's routes with below,
mount MyEngine::Engine => "/"
This would solve your problem.
Though you can make this approach work, the semantics do not create a clean architecture. You can surmise this from the duplication of the Users controller - which implies that some User functionality is handled in the AppEngine, and some is handled in the parent app itself.
Instead, think about what functionality exists uniquely within the app, and which is packaged into the AppEngine gem. Perhaps with JobEngine, as you call it, your Users controller there is actually a UsersStatisticsController and, in the app, the controller there is the 'true generic' UsersController that handles CRUD, profiles, message queue, etc.
If you feel you must unify them into a single controller (rather than giving them distinct nomenclature), then you are best to create a Namespaced controller, where the various functionality can be conjoined thereby.
Even though this adds complexity, it's generally arguable that this is the most sound solution. Here's another post on SO about it
I have a Rails app that has a similar setup to Tumblr, that is, you can have either:
(1) Subdomain hosting (your-username.myapp.com)
(2) Domain hosting (your-username.com)
Both would forward to a personalized website for that user, created with my application.
How can I accomplish this in Rails? I have been able to get (1) working with subdomain-fu, but I'm not sure how to get (2) working. Any pointers (plugins, gems, tutorials), etc. would be greatly helpful, I can't seem to find any.
Thanks!
The principle for domains is the same as the subdomain - find the domain, map to an account.
The details will depend on how your hosting is going to handle the DNS.
I am currently using Heroku and its wildcard service.
In this case, the domain is mapped with a cname to the subdomain hosted by my Heroku app. From here I can work out the associated account and details.
EDIT: I've found a much easier way: http://www.arctickiwi.com/blog/7-host-and-domain-based-routing-in-ruby-on-rails
Not exactly an answer but this is the best I can give. Maybe this'll help you too.
Ideally, this blog post from transfs.com and subdomain-fu should do the trick. I've been trying to implement it, however, and they don't seem to play nicely together.
Basically, if I don't include the intiializer, the subdomain route works fine. If I include the initializer, the subdomain route breaks (everything gets caught by map.root). I have a feeling it's with the way it builds the condition string in the initializer. If you can figure out how it breaks, then you'll have a working app.
My initializer:
module ActionController
module Routing
class RouteSet
def extract_request_environment(request)
env = { :method => request.method }
env[:domain] = request.domain if request.domain
env[:host] = request.host if request.host
env
end
end
class Route
alias_method :old_recognition_conditions, :recognition_conditions
def recognition_conditions
result = old_recognition_conditions
[:host, :domain].each do |key|
if conditions[key]
operator = "==="
if conditions[key].is_a?(Regexp)
operator = "=~"
end
result << "conditions[:#{key.to_s}] #{operator} env[:#{key.to_s}]"
end
end
result
end
end# end class Route
end
end
My routes (just for development). You'll see my local development domain, stiltify.dev. Sorry, I tried to make it look good in here but I couldn't get the code block to look nice. I put it on pastie instead: http://pastie.org/940619.
The comments section in Ryan Bates' screencast was very helpful, and got me to figure out the subdomain => false and the other errors they were getting into. Still didn't fix the problem though!
I need to use one of the resourceful controllers plugins - resources_controller/ resource_controller/make_resourceful as I have several polymorphic models and the models have to be either initialized/build depending on the route.
For example:
www.example.com/groups/1/pages
www.example.com/projects/1/pages
where page acts as polymorphic object as both Group and Project have many pages. So I am thinking of using one of the aforementioned plugins to make pages_controller adapt to both routes. All three plugins works fine and differences are just their implementation of recognizing the routes and loading the models based on that.
Now I want to add sub-domain support using Subdomain_fu plugin so the above example would be:
Site1.example.com/groups/1/pages
Site1.example.com/projects/1/pages
Site2.example.com/groups/2/pages
Site2.example.com/projects/2/pages
On looking at all the three plugins, I don't see any way for them to start loading the resources from my subdomain object, as the subdomain is not part of the route. Any advise on what I am trying to accomplish in a dry/restful way?
I don't know how to do that with resources_controller but i was able to pull off the same thing with the inherited_resources plugin.
Here is how i accomplished it:
In my application controller I set up a before_filter to find the subdomain:
def set_subdomain
#subdomain = Subdomain.find_by_url( request.host )
end
Then in my controllers Using inherited resources I set the #subdomain association using the very cool method "begin_of_association_chain"
protected
def begin_of_association_chain
#subdomain
end
Agile web development has great documentation.