Rails 3, large multi-step form: 1 large controller or separated by resource? - ruby-on-rails-3

I have a multi-step form where the user fills out info on several different pages. In conventional rails, you keep each resource separate in its own controller and you use the REST actions to manipulate the data.
In the conventional system I would have 3-5 different controllers (some steps are optional) for a single multi-step form. There's no real sense of "order" in the controllers if I do it the conventional way. A new developer coming on to the project has to learn what steps map to what steps and so forth.
On the other hand, I have thought about breaking convention and having a single controller that organizes the entire multi-step form. This controller would be full of methods like:
def personal_info
# code...
end
def person_info_update
# code...
end
def residence_info
# code...
end
def residence_info_update
# code...
end
# many more coupled methods like the above...
This single controller will get fairly long, but it's essentially a bunch of coupled methods: one for showing the step (form) and the other for updating and redirecting to the next step.
This would be breaking rails convention and I would have to setup my own routing.
But I'm curious how others have solved this problem? I know both CAN work, but I would like to know which is easier to maintain and code with in the long run.

A resource does not equal a page. I suspect that both ways would break a constraint on REST.
All of your interests have been with the View domain, which resides in your browser. If you want to display a single form in multiple parts you should do so using HTML, CSS etc.
Otherwise your just creating temporary storage on your servers for the forms progress.

I did something like this with https://github.com/pluginaweek/state_machine
The idea was to have one state per step of the form and simply render a different form partial depending on which state the actual resource has. The above gem let's you specify validations and callbacks for each states.
Like this, you can use the standard REST controller actions.

Related

OOP - How to pass data "up" in abstraction?

I have run into a problem when designing my software.
My software consists of a few classes, Bot, Website, and Scraper.
Bot is the most abstract, executive class responsible for managing the program at a high-level.
Website is a class which contains scraped data from that particular website.
Scraper is a class which may have multiple instances per Website. Each instance is responsible for a different part of a single website.
Scraper has a function scrape_data() which returns the JSON data associated with the Website. I want to pass this data into the Website somehow, but can't find a way since Scraper sits on a lower level of abstraction. Here's the ideas I've tried:
# In this idea, Website would have to poll scraper. Scraper is already polling Server, so this seems messy and inefficient
class Website:
def __init__(self):
self.scrapers = list()
self.data = dict()
def add_scraper(self, scraper):
self.scrapers.append(scraper)
def add_data(type, json):
self.data[type] = json
...
# The problem here is scraper has no awareness of the dict of websites. It cannot pass the data returned by Scraper into the respective Website
class Bot:
def __init__(self):
self.scrapers = list()
self.websites = dict()
How can I solve my problem? What sort of more fundamental rules or design patterns apply to this problem, so I can use them in the future?
As soon as you start talking about a many-to-many parent/child relationship, You should be thinking about compositional patterns rather than traditional inheritance. Specifically, the Decorator Pattern. Your add_scraper method is kind of a tipoff that you're essentially looking to build a handler-stack.
The classic example for this pattern is a set of classes responsible for producing the price of a coffee. You start with a base component "coffee", and you have one class per ingredient, each with its own price modifier. A class for whole milk, one for skim, one for sugar, one for hazelnut syrup, one for chocolate, etc. And all the ingredients as well as the base components share an interface that guarantees the existence of a 'getPrice' method. As the user places their order, the base component gets injected into the first ingredient/wrapper-class. The wrapped object gets injected into subsequent ingredient-wrappers and so-on, until finally getPrice is called. And each instance of getPrice should be written to first pull from the previously injected one, so the calculation reaches throughout all layers.
The benefits are that new ingredients can be added without impacting the existing menu, existing ones can have their price changed in isolation, and ingredients can be added to multiple types of drinks.
In your case, the data-struct being decorated is the Website object. The ingredient classes would be your Scrapers, and the getPrice method would be scrape_data. And the scrape_data method should expect to receive an instance of Website as a parameter, and return it after hydration. Each Scraper needs no awareness of how the other scrapers work, or which ones to implement. All it needs to know is that a previous one exists and adheres to an interface guaranteeing that it too has a scrape_data method. And all will ultimately be manipulating the same Website object, so that what gets spit back out to your Bot has been hydrated by all of them.
This puts the onus of knowing what Scrapers to apply to what Website on your Bot class, which is essentially now a Service class. Since it lives in the upper abstraction layer, it has the high-level perspective needed to know this.
One way to go about this is, taking inspiration from noded structures, to have an atribute in the Scraper class that directly references its respective Website, as if I'm understanding correctly you described a one-to-many relationship (one Website can have multiple Scrapers). Then, when a Scraper needs to pass its data to its Website, you can reference directly said atribute:
class Website:
def __init__(self):
self.scrapers = list() #You can indeed remove this list of scrapers since the
#scrapper will reference its master website, not the other way around
self.data = dict() #I'm not sure how you want the data to be stores,
#it could be a list, a dict, etc.
def add_scraper(self, scraper):
self.scrapers.append(scraper)
def add_data(type, json):
self.data[type] = json
class Scraper:
def __init__(self, master_website):
#Respective code
self.master = master_website #This way you have a direct reference to the website.
#This master_website is a Website object
...
def scrape_data(self):
json = #this returns the scraped data in JSON format
self.master.add_data(type, json)
I don't know how efficient this would be or if you want to know at any moment which scrapers are linked to which website, though

Parsing and mapping REST-like formatted URIs for custome event handling (iOS)

I need to implement a custom event handler, which should for example handle URIs like:
- SomeAppName://SomeDomainClassName/ID to fetch a record from a database table
or
- SomeAppName://SomeControllerName/PushView/SomeAdditionalOptions to push a view controller and set additional options, for example this could be a calendar view which should be focused to show the calendar at a certain date.
I have been searching for existing REST frameworks, but so far I didn't figure how any exising framework could allow me to define formats for URIs and map them to local classes, actions, whatever it will be.
How could I 1) define and interpret REST like URIs and 2) map them to local actions or objects, without reinventing the wheel (e.g. inheriting from RESTKit)?
Or should I end up to write my own parser? In that case, pointers to good REST like URI lex/flex are welcome.
What I was looking for is called an URL router in Ruby worlds. There exist a few also for Objective C, more or less useful.
I ended up to write a custom URL Router, that is like ruby URL routers just split into basically two components (router and route). For the Router part (the mapper and URL dispatcher so to say) I looked at TTURLMap, which is part of Three20, but threw away 90% of code and changed the action handling to fit my needs. It has lot's of boilerpate code, but basically was what I needed for getting an idea for the router.
For the particular route handling I use SOCKit, which seems great and has well tested code.
Now I can for example have a local function hello which takes two params to show some values passed as URL:
Roter *router = [[Router alloc] init];
[router map:#"soc://:ident/:saySomething" toInstance:self with:#selector(hello:sayWhat:)];
[router dispatch:#"soc://3/hi"];
I'll add blocks as well, but for most cases selectors work well, because SOCKit passes them the actual values for basic parameter types (no need to use parse the dictionary with values from the URL).

Rails 3: Choose and run a Mechanize script from inside Rails action.

My application scrapes information from various sites using Mechanize. Naturally, each site requires custom Mechanize code. Each site is stored in my database, including the url to scrape and the string name of an .rb file containing that site's Mechanize code. For this case, let's assume the scripts are available in the assets folder.
I would like to call http://example.com/site/:id, then have the show action dynamically choose which Mechanize script to run (say, #site.name + ".rb" ). The script will massage the data into a common model, so all sites can use the same show template.
I can't find a way to dynamically load a .rb script within an action and obtain the result. It may be easier to have the scripts return a JSON string, which I can parse before passing on to the template, but I can't see a solution for that either. Ideally, the script will run in the action's scope. The ugly solution is an enormous if-else chain (testing the site name to determine which code block to run), but there must be a better way.
Any suggestions would be greatly appreciated, as would any general solutions to running different code dependent upon the properties of database objects.
If you have all the code in your app already why are you eval'ing Ruby code?
Create classes like:
class GoogleSpider < Spider; end
class NewYorkTimesSpider < Spider; end
class SomeOtherSpider < Spider; end
And the site class will hold the class name that will be used, so you would be able to easily do something like this in your controller action:
def show
#site = Site.find(params[:id])
# name contains SomeOtherSpider
#process_output = #site.name.constantize.new.process
# do something with the output here
end
And then you don't need to mess around evaluating Ruby code, just call the class needed. You can even make them all singletons or keep them all in a hash for faster access.

How should I create half-day events in Rails

I'm creating an app in Rails that is essentially a holiday management tool. Employee requests holiday; email sent to manager for approval; manager approves/rejects etc.
The app will allow whole or half-day holidays to be taken and I'm wondering about the best way to handle the half-days. I don't want to present the user with a time picker. I would prefer to offer a date-picker and AM/PM checkboxes.
I suppose I'm looking for opinion on whether I should 1) use the chosen date in conjunction with say the AM checkbox to create a DateTime entry in the DB e.g. leave starts on 10 February in the AM = "2011-02-10 00:00" or 2) should I simply record a Date in the DB with a string reference to AM in a separate field.
I want to output leave in the form of .ics files and a stream so the first option to me makes the most sense but is likely to create a real fudge in the code. Any thoughts or further options appreciated.
Thanks
Robin
Why not create durations (pairs of datetimes) for every holiday rather than just one? That should model the ical representation better than just storing single times as events.
As far as how to handle that at the view level, you're probably going to want to use the Presenter Pattern since you're really manipulating events rather than times.
A presenter is basically a proxy with added business logic that represents a better mapping for how the view interacts with the model.
It's a lightweight layer (they're normally just normal Ruby classes, rather than AR::Base or other heavyweight rails models) that wrap your models, and are usually instantiated at the controller level, and passed to your views rather than the model themselves.
http://blog.jayfields.com/2006/09/rails-model-view-controller-presenter.html
http://blog.jayfields.com/2007/03/rails-presenter-pattern.html
http://www.slideshare.net/adorepump/presenting-presenters-on-rails
Here's what I mean: https://gist.github.com/984025

Need guidance in creating Rails 3 Engine/Plugin/Gem

I need some help figuring out the best way to proceed with creating a Rails 3 engine(or plugin, and/or gem).
Apologies for the length of this question...here's part 1:
My company uses an email service provider to send all of our outbound customer emails. They have created a SOAP web service and I have incorporated it into a sample Rails 3 app. The goal of creating an app first was so that I could then take that code and turn it into a gem.
Here's some of the background: The SOAP service has 23 actions in all and, in creating my sample app, I grouped similar actions together. Some of these actions involve uploading/downloading mailing lists and HTML content via the SOAP WS and, as a result, there is a MySQL database with a few tables to store HTML content and lists as a sort of "staging area".
All in all, I have 5 models to contain the SOAP actions (they do not inherit from ActiveRecord::Base) and 3 models that interact with the MySQL database.
I also have a corresponding controller for each model and a view for each SOAP action that I used to help me test the actions as I implemented them.
So...I'm not sure where to go from here. My code needs a lot of DRY-ing up. For example, the WS requires that the user authentication info be sent in the envelope body of each request. So, that means each method in the model has the same auth info hard coded into it which is extremely repetitive; obviously I'd like for that to be cleaner. I also look back now through the code and see that the requests themselves are repetitive and could probably be consolidated.
All of that I think I can figure out on my own, but here is something that seems obvious but I can't figure out. How can I create methods that can be used in all of my models (thinking specifically of the user auth part of the equation).
Here's part 2:
My intention from the beginning has been to extract my code and package it into a gem incase any of my ESP's other clients could use it (plus I'll be using it in several different apps). However, I'd like for it to be very configurable. There should be a default minimal configuration (i.e. just models that wrap the SOAP actions) created just by adding the gem to a Gemfile. However, I'd also like for there to be some tools available (like generators or Rake tasks) to get a user started. What I have in mind is options to create migration files, models, controllers, or views (or the whole nine yards if they want).
So, here's where I'm stuck on knowing whether I should pursue the plugin or engine route. I read Jordan West's series on creating an engine and I really like the thought of that, but I'm not sure if that is the right route for me.
So if you've read this far and I haven't confused the hell out of you, I could use some guidance :)
Thanks
Let's answer your question in parts.
Part One
Ruby's flexibility means you can share code across all of your models extremely easily. Are they extending any sort of class? If they are, simply add the methods to the parent object like so:
class SOAPModel
def request(action, params)
# Request code goes in here
end
end
Then it's simply a case of calling request in your respective models. Alternatively, you could access this method statically with SOAPModel.request. It's really up to you. Otherwise, if (for some bizarre reason) you can't touch a parent object, you could define the methods dynamically:
[User, Post, Message, Comment, File].each do |model|
model.send :define_method, :request, proc { |action, params|
# Request code goes in here
}
end
It's Ruby, so there are tons of ways of doing it.
Part Two
Gems are more than flexible to handle your problem; both Rails and Rake are pretty smart and will look inside your gem (as long as it's in your environment file and Gemfile). Create a generators directory and a /name/name_generator.rb where name is the name of your generator. The just run rails g name and you're there. Same goes for Rake (tasks).
I hope that helps!