Ruby on Rails MVC Question - ruby-on-rails

I intend to store in a database a minimal amount of information pertaining to a book (title, isbn). However, on display I'd like to display additional attributes (pages, author, cover image) not stored in the database. I plan on getting this information from the Amazon Web Services (AWS) using Ruby/AWS. I am very new to Ruby on Rails and am not sure exactly how this would/should be performed.
Some options that spring to mind include modifying the books controller or creating an entirely separate model based on the Amazon entities that relies upon searching for books listed only in my database.

Your ActiveRecord book model can be customized to retrieve the additional attributes from AWS. Your view and controllers will be clueless and DRY.

When you ever need to deal with any data, in any MVC environment, it needs to go in the model. You could create an additional other_information method that uses ||= to either get the other information from AWS or returns the information from an instance variable. Either that or you could create a find_with_info method that gets it all at the same time :)
But defiantly keep any data-related tasks in the model.

I would suggest creating methods in the model. Are you always going to be pulling the extra info every time you show these entries? If not you will want to maybe have a different controller action for either the "extended" (ie with amazon info) or "limited" (ie without the amazon info) and have the other be the standard. This way you can pull exactly what you want when you want it and make sure you hit amazon only when you need to, not with every single show or index call.

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).

Creating a no-database rails model that would serve as a view to index data in elasticsearch

I'm facing a complex problem which i haven't been able to resolve yet.
I'm using Rails 4(edge) with postgresql 9, ElasticSearch 0.20.6 and the gem Tire (0.5.7).
I have multiple table that are linked together. for instance:
Agency has many Clients
Clients has many Projects
Projects has many Files
My goal here is to be able to index Files in two ways:
First have an index that just allows easy and rapid search among all files. That i have succeeded into doing just by using tire. My index has a type "file" and it works like a charm.
The other index I would like to create would have some of the files information but also some of the clients and the agencie's properties. This is for an external tool that would be able to fetch the best files according to criteria like the project's category or the client's location...
As i'm using postgresql, i was thinking i could do a database view and index data from there. I'm not sure it's good to do it like that though cause the view would be pretty complex with multiple joins. Plus i'm afraid that any update would trigger a full-database re-indexing.
I was wondering if there was a way to do a pure-tire model and easily trigger the index update on any of it's linked tables.
For instance, i'll have indexed the data in a type named files_front. I would have a model FilesFront which has_one :file and each time i update a file or any parent, all the impacted files would see their values updated in ES.
I'm really not sure on how to do this, so any advice is welcome.
Having a separate, table-less or standalone model is a good solution. The problem here, I assume, is connecting the FileFront class to the rest of the system. Effectively, whenever you update the File or any associated Client etc. object, you need to update the FileFront object.
You could actually use the Model::Persistence to that. So for each File you'd have an associated FrontFile, which you would assemble as JSON in File and create/update in an after_save callback. The tricky part is ensuring changes to the parent objects are propagated to file, and vice-versa.

Ruby on Rails: how to use sessions to implement remote sign-out?

My goal is to allow users of a Rails web app to see all their open sessions on other computers and close/sign out of them remotely. Similar to gmail's "Account activity" page (link found at the bottom of the gmail inbox page).
I can technically achieve this by using the sessions in the database
account_sessions = CGI::Session::ActiveRecordStore::Session.find(:all)
and iterating over them to find sessions corresponding to the current user (the user ID is stored in the session data), and allowing the user to destroy these sessions.
However, this doesn't offer the usual convenience of working with Rails models. I can't easily express a has_many relationship with the user and make use of
current_user.sessions
nor can I easily put an index on user_id since it's in the data part of the session (instead of being its own column).
This approach also may become impractical if the number of sessions grows, since in the above the table is read into memory.
As a solution, I'm thinking of creating my own model which "mirrors" the relevant portions of the session and is created/updated/destroyed to maintain that correspondence.
This isn't a great way to go about it due to data replication and added complexity of code, but I didn't find another way to do it.
So the question is: is this a good way to go about it, or am I missing something?
Thanks in advance!
Fraser
Edit: I should have mentioned that I'm currently using restful-authentication, and would prefer not to switch.
Since authlogic offers a user session model and is easily extendable, you should be able to achieve exactly what you want, if you don't mind to switch to another authentication mechanism.
Edit: This Railscast should give you a pretty good overview.

Considering a new Rails app with existing data (not a db, actual data) -- what is the best way to proceed?

I have been tasked with developing a new retail e-commerce storefront for my current job, and I am considering tackling it with RoR to A) Build a "real" project with my limited Rails knowledge, and B) Give management quick turnaround and feedback (they are wanting to get this done ASAP and their deadlines are rather unrealistic - I'm talking a couple of weeks to go from nothing to working model so they can start to market it with SEO/SEM and, I kid you not, "video blogging" because my boss heard that's the future).
We do have a database structure in place but it's absolutely terrible and was thrown together without rhyme nor reason, so I'm going to largely ignore it and create a new database from scratch; however, I have existing data that I need to load into the application (like I said, it's an e-commerce app and we have the product data). I need to massage this data into a usable format because our supplier provides it to us with cryptic, abbreviated column names and it's highly denormalized, especially in the categories (I've posted a question regarding it before - basically the categories table has six fields, one for each category/subcategory, with some of them being blank if that category doesn't apply).
There are two main issues that are giving me second thoughts:
As I said the data needs to be put into a "proper" database schema; I can't just load it as-is. I have some thoughts as to a good data model for it, but my analysis is not completed yet. There would end up being a large amount of joins tables to link various things together (e.g. products_categories, products_attributes, products_prices) etc and these tables would link products not via an ID but by their SKU (see below).
Everything already has an ID that's generated for it, but anything new I add needs to have one autogenerated; I doubt this will be a problem with any mature RDBMS, but I know Rails likes to generate IDs itself. Also, almost all of the product-related tables are linked by SKUs (and in the data provided by the supplier are actually a composite key consisting of the prefix and stock number, which combined make up the full SKU), not by IDs and I'm not sure if this will be a performance issue (of course, I could always manually create indexes on these columns to speed it up). It does mean that I'll need to break away from the Rails conventions, however.
In short, I think that Rails might be a good choice as far as time-to-market and ease-of-development, but having to work with the existing data content might turn into a pain because the application will need to be developed around that, instead of the "traditional" Rails app, and that factor is giving me major doubts about using Rails. There are also some other issues (having to set up a Linux server, and the fact that the area I live in has very few Rails developers so if I left the company I'd basically be holding them hostage as far as updates/modifications). I'm really unsure as to the best path to proceed.
I would develop the app as if you didn't have the data. Use the ORM and make your database the best it can be, but of course keep in mind what data you have to populate it with (eg: don't make crazy new constraints for things that will leave you going through old data record by record).
When you're done and tested, write an import script that pulls your real data onto your new database.
It's not that different from the conventional design/development model... Apart from you can do your data-input in a semi-automated fashion.
I was in the same situation not too long ago — a crappy PHP app that held ten years worth of all company data.
What I did was simply create a Migration model and added methods to import each resource.
class Migration
def migration_all
self.jobs
end
def self.jobs
...
end
end
The cool thing about this is that you can arrange which order resources are imported as one will likely reference another. I also added methods that directly modified the db schema. One nice trick if you have to keep an existing primary key is to create a field named 'legacy_id', copy over your existing primary key, and when you're done, simply remove the 'id' field, rename the 'legacy_id' field to 'id', then add the primary_key constraint on the new 'id' field.
Don't use the SKU as the unique key for each product - use the standard Rails incremented id.
SKU could change as it may be misentered, etc and that would make it a nightmare to change all of the references from other tables. Put your current id in a sku column, index it and update the references in your other tables to the Rails ids.
You'd be able to do Product.find_by_sku(params[:sku]) in your controllers, set up a /products/:sku route, etc. I don't see what you'd gain (other than a headache) by using your non generated ids as the database primary keys.
I'd also suggest running your old data through your app's validations to make sure you are not loading up a bunch of inconsistencies and erros. It will help your app run smoothly and highlight existing data errors at a point where you can fix them.
Don't assume the existing data is valid just because it is already there.

Non persistent data in a Rails app

I'm working on an "analytics" page for a rails app. The analytics page does not persist any data of its own (it's very primitive at this point) but does utilize metrics that I'm grabbing from the DB (via the aggregate expressions built into ActiveRecord). Aside from gathering and presenting the metrics the only other requirement I have is to allow the user to provide a date range to filter the data. Up to this point I have been using instance variables and the like to store the metrics information...as the number of metrics grow along with the need to manage the start and end filter dates I begin thinking that I should put this data into its own model. If I do move all of my "data" into a model should I just use a plain object with attr_accessors or is there a more appropriate base class I could use for non-persistent data? I'm familiar enough with a MVC architecture to know that my controller is getting to bloated but no familiar enough with rails to determine how I should organize my data/logic in this case.
Any insight would be greatly appreciated!
It sounds like you could use a Rails non active-record model. There's a good Railscast about that :
http://railscasts.com/episodes/121-non-active-record-model
Hope that helps,
You're on the right track here. Many applications have classes inside app/models that do not inherit from ActiveRecord::Base. Any time you find yourself managing lots of arbitrary variables inside controller actions, it's a good place to consider abstracting that data into a non-persistent model.
This is an area that's not well documented at present, probably because the ActiveRecord stuff is sexier?
I went through the same process, finding my controller actions were becoming uncomfortably large and full of logic as I strove to construct my derived data from ActiveRecord-based models, which in turn started to acquire additional responsibilities that they didn't really want or need.
Once I got the same advice you're getting now the whole thing simplified magnificently.

Resources