Adding a "tools mode" to rails app - ruby-on-rails

Let's say I have a rails app with content that's read-only to the public, but I'd like to build tools to edit that content (or use scaffolding). I don't want to expose create/update/delete actions publicly (even if password-protected), but I'd like to have a server with this functionality inside a local network that interacts with the production database.
So I'm thinking of writing a plugin for this, which would add a tools rails environment (like development, production, and test) and a way of configuring a controller method as "tools-only". When not in tools mode, requests for any tools-only action gets redirected to a standard 404 page.
Before I start reinventing a wheel, does something like this already exist? Are there perhaps better ways to solve this problem?

Interesting idea - Aside from creating the custom environment wouldn't it just be one before_filter in your Application controller?
before_filter :can_access_tools, :except => [:show, :index]
Other controllers would just skip it as need be.

Why do it as a separate environment? What I would do (and have done) is put the editing functionality in a separate namespace (I usually call it admin), then using a before filter only allow a user with an admin role access to those controllers. So if your app is displaying widgets, you could see them in the normal app behind the url /widgets. In order to edit them you would go to /admin/widgets (and also have to be logged in as an admin). Instead of just doing it via route namespaces, I also create an AdminController that all other controllers in that namespace extend. Then you can put any filters that need to apply to all of them in one place.
You could get the UI for this up pretty quick by dropping in something like Active Scaffold to provide a pretty clean interface to do CRUD operations on it. You could also take a look at Streamlined or Hobo for this part as well.
I often set up extra environments for testing multiple contexts, but for this case it seems like overkill. If you limit the editing functionality by authorization (requiring the role of admin) instead of by access (only the local server can get to it), it also allows you to make changes if you're on the road and not in the office.

umm...i know herokugarden allows you to edit your code online through a browser, will that work?
here is a link to the demo

Related

Rails, handle two sites with different url and design but with the same db

I'm looking for the best way to solve a problem.
At this moment I have a site for a customer, example.domain.com
My customer ask to create another website with some changes in design, but the contents are the same of the first website. I don't want to duplicate the website, because every feature I add to the site A must be deployed also to site B, and I'm looking a smart way to handle the situation.
I need to keep two different domains and I need also custom mailers and other small tweaks in the controllers (and maybe in some models).
My idea is to put in application controller a before filter like this
before_action :detect_domain
private
def detect_domain
case request.env['HTTP_HOST']
when "example.domain.com"
request.variant = :host1
when "example1.domain.com"
request.variant = :host2
end
end
Then I use the variant with some conditional to choose the mailer, to customize the views and to apply some code changes.
Any other idea?
Using a before filter and a per-request variable like your proposal will work, with a couple caveats that I'll mention below. I'd recommend a tool like the request_store gem to actually store the per-request value of which "skin" is selected.
Now, for the caveats. First, the main problem with per-request variables is that your Rails app does not always exist in the context of a request. Background jobs and console sessions operate outside of the usual request/response flow of your app. You will need to think about what happens when your models or other non-controller/view code is executed when that variable isn't set. I would suggest simply not having your models depend on RequestStore at all -- have the controllers pass any request-specific information down into the models, if needed.
Secondly, it's not clear from your description if you want any data or logical separation between the two domains, or if you just want different look-and-feels. If the former, you might consider the apartment gem, which aims to make database multi-tenancy easier.
EDIT: I also want to mention that, as an alternative to the multi-tenant solution above, you also have the option of a multi-instance solution. Wherein, you use an environment variable to indicate which version of the site should be displayed, and spin up multiple instances of your app (either on the same server with a reverse proxy, or on separate servers with separate DNS entries or a reverse proxy). The downside is increased infrastructure costs, but the context problem I mentioned above no longer exists (everything always has access to environment variables).

Multisite application in Rails (like shopify.com)

I would like create web app like shopify.com.
User can pickup subdomain(or domain), theme and have own store.
How can I do this?
Create main application, deploy it automatically like new standalone version and update it via git?
I'm using Rails 3.
Thanks for your advice.
Based on replies:
When I choose to use only one application (without multiple instances) and give user his subdomain, it will looks like their own website. But everything will be in one database (It's good idea?). And how can I have multiple themes in Rails app?
Take a look at LocomotiveCMS, specifically the routing system. Locomotive actually hosts multiple sites inside a single rails application. It does this by inspecting the request URL when it comes in and setting the current_site variable with the site which is set up to handle the domain. Then the current_site is actually just an object which contains all the pages, contents, settings, etc. for the specific site being served up.
So to answer your question, I think a good solution is to give your rails app the ability to serve up multiple sites based on the domain. It's not that hard, and it seems less fragile to me than trying to automatically deploy new instances of an app.
So far I have understood, you want to let your users have their own subdomain, different theme but the functionality would be same right. Users just need to have a feel of something of their own.
Well definitely, you need to have a single application that supports multiple subdomains.
A quick googling gave me [ http://37signals.com/svn/posts/1512-how-to-do-basecamp-style-subdomains-in-rails ]. May be you can get some insights from here.
For example if your service is http://www.myfi.com, a brief idea can be:
When a customer is registering, you should let him choose his subdomain. And the newly created account will be associated with this subdomain with a url. Say, http://customer1.myfi.com.
You should register for domain *.myfi.com so that anyone in the world hit with anysubdomain.myfi.com, it comes in your application.
Then from the url part, you should identify the subdomain (customer1) that is being used, and need to set that in session.
Now when someone will try to login, you must verify the account in the context of that subdomain's account.
In fact, all following actions need to be handled in the context of the subdomain's account.
Just tried the gather a glimpse of the implementation here. If you have confusion about something specific, share that also.
Edit:
Whenever you are thinking about multiple theme, you must have simple design which is completely driven by css and js. The app/view files should contain only content and HTML nodes with class names or ids.
Generally a UI designer can put more helpful ideas about how to make such theming mechanism. But all I can feel is, based on the chosen theme by customer, you have to load different css and js.
Actually the strategies can be indefinitely sophisticated and scalable, but its always wise to start with something easy. Then ideas will automatically evolve into better ones.

Rails 3.1 Custom Controllers and Views w/ Default

Background:
I'm building an app that lets users create their own website (e.g., mywebsite.alexlod.com)
Each website owner is affiliated with me, so I'll trust them to write their own rails code
Each website should have default controllers and views, except when one of these owners creates their own
Here's how I envision controllers working:
I'm thinking that what's in app/controllers/ will be the default, but when a file is specified in a <subdomain> top-level directory, that file will take precedence over the default.
Let me give an example. Let's say one of my website owners (foo.alexlod.com) wants to tweak app/controllers/photos_controller.rb. They should be able to create foo/controllers/photos_controller.rb whereby their controller is used instead of the default. I'm thinking the correct approach here has something to do with routes and the load path, but I'm new to Rails and Ruby and could use some guidance.
As for views, I would like them to work much the same. When a view or partial is defined in <subdomain>/views/, that view is used instead of the default located in app/views/.
I realize my plan here violates the default rails directory structure. But this approach has gotta be more simple than the alternative - case statements in each controller action. Unless there's an even better alternative?
I believe engines may be the way to go for what you want. That link is a little old but still should be applicable with Rails 3.1. Each subdomain's controllers and views can be placed in their respective engine folder.
Now, you just need to figure out which engine to load per request. That's the part I think may be the deterrent to your idea -- you don't want to be loading and unloading code all the time in production.
You may want to opt for a templating language like Liquid, in that case. That, however, gives a lot less control to the users.
I may have a partial answer for you as it sounds like you want to do something very similar to what I am doing for the mobile version of my site. After I identify that a user is mobile I add a mobile directory to the path to override any views that I have optimized for mobile. If the view doesn't exist in the mobile directory it defaults to the default view.
Here is what I did for views:
in app/controllers/application_controller.rb
before_filter :prepend_view_path_if_subdomain
def prepend_view_path_if_subdomain
unless pSubdomains.blank?
subdomain = request.subdomain.first
#This will add the subdomain view directory to the view path before the default
#Rails view directory and any views here will be picked up and rendered.
prepend_view_path 'app/' + subdomain + '/views'
end
end
Doing the same thing for controllers, however, is a little trickier due to routing. There is no prepend_controller_path method that is equivalent to prepend_view_path. Honestly I'm not sure how to approach this, you could use your case statement approach or possibly dynamically forward on the request to the subdomain controller (it if exists). I think it might be possible to add a before_filter to your controllers that evaluates each request much like I show above with views and then determines which controller should be used.
I also stumbled across this question: Rails 3.1 load controller from different path based on subdomain, not sure if it helps you or not.

Multi domain rails app. How to intelligently use MVC?

Background:
We have app a, b, and plan to add more apps into this same application. The apps are similar enough they could share many views, assets, and actions. Currently a,b live in a single rails app(2.3.10). c will be similar enough that it could also be in this rails app.
The problem:
As we continue to add more apps to this one app, there's going to be too much case logic that the app will soon become a nightmare to maintain. There will also be potential namespace issues. However, the apps are very similar in function and layout, it also makes sense to keep them in one app so that it's one app to maintain(since roughly 50% of site look/functionality will be shared).
What we are trying to do is keep this as clean as possible so it's easy for multiple teams to work on and easy to maintain.
Some things we've thought about/are trying:
Engines. Make each app an engine. This would let us base routes on the domain. It also allows us to pull out controllers, models and views for the specific app. This solution does not seem ideal as we won't be reusing the apps any time soon. And explicitly stating the host in the routes doesn't seem right.
Skinning/themes. The auth logic would be different between the apps. Each user model would be different. So it's not just a skinning problem.
In app/view add folder sitea for sitea views, siteb for siteb views and so on. Do the same for controllers and models. This is still pretty messy and since it didn't follow naming conventions, it did not work with rails so nicely and made much of the code messier.
Making another rails app. We just didn't want to maintain the same controller or view in 2 apps if they are identical.
What we want to do is make the app intelligently use a controller based on the host. So there would be a sessions controller for each app, and perhaps some parent session controller for shared logic(not needed now). In each of these session controllers, it handles authentication for that specific app. So if the domain is a.mysite.com, it would use session controller for app a and know to use app a's views,models,controllers. And if the domain is b.mysite, it would use the session controller for b. And there would be a user model for a and user model for b, which also would be determined by the domain.
Does anyone have any suggestions or experience with this situation? And ideally using rails 2.3.x as updating to rails 3 isn't an option right now.
Devise does exactly this. You would do well to check out its architecture and apply that architecture to your own case.
You will have multiple separate Rails applications. The shared code will be a separate project, perhaps distributed as a gem or at least a separate Git repository. The shared code will include many controller actions and many view templates that are there to be sensible defaults, and which will be overridden in some apps but not in others.
All the custom code for application A will belong in a project solely devoted to containing the custom code for application A. It will be its own fully-functioning Rails application and will depend heavily on the majority of the sensible defaults provided by the shared code in the shared-code project.
I've used the theme support plugin before and dynamically set the theme based on the request uri:
http://mattmccray.com/svn/rails/plugins/theme_support
It will probably need some work to support Rails 2.3.
Update: Looks like there's a rewrite: https://github.com/dasil003/rails-multisite
Sounds like you want to make the 'base' app a plugin and use that in each of your site apps. You can use something like svn-extern so it's automatically updated whenever something changes.

How to turn a single-site app into a mantainable multi-site app without code changes?

It's an application that we use internally at the office that I would like to offer as a hosted service for anyone.
How can I do that without making major code changes?
The first thing that occurs to me is to have the app select which database to connect to based on the domain.
So each instance of the app would have its own database, but all instances would share the same code.
The only changes required to the code would be the database selection.
Is this approach maintainable? I've heard wordpress.com does this and that it offers a couple of advantages. I'm mainly looking to do it this way to avoid have to scope my entire set of database queries to a certain site within the same database.
Thanks!
The simplest way to do this is to clone the application, and create another server instance to handle it. This actually the way I handle multiple wordpress blogs on my server
Pro:
This process can be streamlined into a utility script.
Can be easily maintained if symlinks are used for the common code. IE: Everything but branding and some of the things in the config directory.
Cons:
- If you're using passenger it will require an apache restart for each new instance.
- Same if you're using Apache to route subdomains on different virtual hosts to different mongrel clusters.
However the better way comes from the question: Rails - Separate Database Per Subdomain
The method in the accepted answer is much more robust. It might require more changes than you're looking for, but it has all the benefits without the drawbacks of any other methods. Each new instance requires a new entry in the master database with the table name and other instance specific information. You'll also want custom rake task to build the database for each new instance.
I would suggest switching the database connection and adding a view_path based on the domain, I have posted code in this question.
I hope this helps!
I wouldn't do this with multiple databases as you mentioned. Keeping all your schemas/migrations in sync with all the db's could become painful.
I would look into simply making it a multi-tenant app where you have some sort of "Account" model and then all your existing models are scoped to it ... in other words, if this was a blog app, your Account has_many :posts, etc.
With this approach, you can identify accounts by subdomain ... have people choose their subdomain when they create an account and go from there.
It's pretty straightforward to do. If you need add billing into the mix, you might look at the SaaS Railskit (which handles all the signup and subdomain stuff) or Chargify.
You can also identify accounts Twitter-style ... with http://myapp.com/someuser

Resources