Rails structure, should I use a service layer in this case? - ruby

I'm new to Ruby and Rails and I'm making my first app. Basically I'm parsing HTML and sending it as JSON to the client.
Right now I've two sources for the HTML data but I could have more in the future. Because of this I thought that it'd be a good idea to remove the code responsible to parse the HTML from the controller and put it into a service layer. I came up with this structure:
app
controllers
main_controller.rb
model
project.rb
task.rb
services
source1_service.rb
source2_service.rb
The MainController call both services to get the projects and tasks; each service parse its own HTML.
Is this a good solution? Is there a more RoR way to do this?

put your services in your models directory, there is no rule that all models have to extend from ActiveRecord::Base, but your services are opaquely data models to the rest of your app (if I understand you right). Ideally, let the service code mimic active record so other people that are just using your model code dont have to know its a different than any other model in your rails app.

Unlike in the Java world, 'the service layer classes' concept is not really popular/used in the RoR world. Its a good idea to remove that code form your controllers (you want your controllers to be thin). But i think you can inject them to your models. If you feel its getting too complicated you can break up your extra code into modules and mixin those modules to your models.
Its not the one and only way of doing things though.
However if parsing HTML include some common logic that can be reused, even in another project its a good idea to put it inside the lib/ folder.

Related

Where Do I Create External API functions or Classes? Proper MVC Structure for Web Frameworks

I am looking to add multiple API's to my senior project on an MVC based framework (Laravel). I understand the basic concept of MVC, but want to make sure that I am doing things according to best practice.
Basically, I am going to have a class/function that takes a query and calls that query on a Amazon's Product API. I have seen an example of calling API's from directly within the Controller on Laravel (see http://www.phplab.info/categories/laravel/consume-external-api-from-laravel-5-using-guzzle-http-client).
Perhaps I don't understand MVC well enough. Should an external API call be in it's own class? And if so, should it be a Controller Class or a Model Class? I hope the Stack Overflow gurus can enlighten me. Let me know if I need to clarify anything!
It depends to what you want to process with external API.
If it's a part of the business, it can be in Model (lot of people put
the business inside the model to follow the encapsulation principle
of OOP).
If it's the explicit process, it should be in Controller
(like most people do).
For example, if you have a model Transaction in bank transfer (that automatically convert the currency, it needs the external API to get the exchange rate), the external API call should be wrapped in model. So controller cannot modify the Transaction object and it will be safe.
In another hand, you can call to external API in controller, do some extra stuffs then set it back to Transaction object. It's also good because model always contains only properties. It makes application also clear enough.
They are 2 ways of use, none is absolutely right or wrong. But if you choose one, follow it, don't mix.
Another, both 2 are only ok. The better way is putting the external calls to other places (modules etc), then call it by single line in model or controller.

Laravel Web and API controller structure. Separate vs DRY

I want to build a Laravel application which users both web and API parts. The common (and mine as well) question is whether to use separate controllers or not.
There are 2 options:
Separate controllers
Laravel API controller structure?
Use one controller and check the request type (is Ajax, or depending on the request link) and return either JSON or HTML.
Laravel resource controllers for both API and non-API use
Those who have the 1-st opinion doesn't explain the DRY problem solution - web and API controllers would be the same except the return statement (JSON or HTML view). But since most post recommend to separate controllers I suspect I don't understand something about the DRY problem solution.
I don't see any disadvantage of the second method. But people say something like
If you use only one controller, you will end up soon with a messy class with thousands of lines. Not only this is not going to scale well, but it will be hard to work with for you and your teammates.
Please explain me the DRY problem solution for the first approach (separate controllers) and the possible underwater rocks in the second approach (single controller)
Please explain which approach is preferable.
I think this is a great question, and I too am keen to see the responses.
I can see the arguments for both approaches. I however would create and maintain separate controllers, whilst using services to share common logic between the controllers where it is known that this will never change.
For example, if you allow users to upload avatar images. I would put such logic in a service and consume this service in both controllers.
The reason for this approach in my mind, is that the web and API logic may diverge and it would therefore be easier to iterate each without impacting the other.
If this is unlikely, then I would still create separate routes, but point them both at the same controllers, so that if it did change in the future, you can simply re-point the API routes to their own controllers.

Rails 3.1 and the lack of a service layer

I'm writing an hotel-like app in Rails 3.1 and I'm new to Rails.
I'd need some advice about how write what is normally managed in the service layer of an app.
The app needs some service to calculate the price, and this methods have to be available for more than one controller. Till now I put all this stuff in a controller but now I have to get it out from there and really I' don't know how and where.
I thought about writing a helper and include it in the controller but I dislike this solution because helpers should only help to render stuff in the view and they shouldn't mess with the business layer related tasks.
How would you code this?
Maybe you can create a folder named services
/app
/controllers
/services
calculation_service.rb
Then you use it on your controllers like this:
def show
#model = Model.find(params[:id])
#total = CalculationService.calculate_sum(#model.price, #model.subtotal)
end
I wouldn't even do this in the controller. I would push the logic to your model if possible. If it's required in multiple models, I'd create a mixin in your lib folder and include it in each model.

How to implement projects in Backbone.js TODOS-app?

Hey! I'm trying out Backbone.js and have followed the annotated source of the TODO's app.
I fail (don't know how this should be done) when trying to implement projects, which has tasks as "children". So that i can change project and view different lists of tasks.
How should i do this? Some tips for beginner tutorials would also be great :)
The backbone docs mention a pattern for doing something like this:
http://documentcloud.github.com/backbone/#FAQ-nested
So, I would create a new model called a project that has a property called 'tasks' which is an instance of a TodoList collection.
I can't speak to storing the data, as I've never looked at the localStorage used in the TODO app.

How to test/spec Sinatra & MongoDB API with Cucumber?

I want to spec a Sinatra server that receives HTTP requests, stores things in MongoDB, and responds with JSON. How would I spec both the MongoDB entries and the responses?
I'd like to use Cucmber and RSpec to do this cause I hear they're hot, but I'm not really good with them yet.
My learning so far with BDD is that you need to think in very small steps. E.g. you could start in making specifications with rspec for your routes, example project with sinatra here, and another example, here.
Then you could start in making specifications for your model layer. Small steps also here, check for validations, setting and getting attributes.
Last, you might approach to specify the view, here you need to learn about mocks and stubs for your controller and models.
Cucumber is a different story in my view. You need to write cucumber specifications when you work with your customer, to understand together the requirements of your app. It facilitates acceptances testing as far as I can see.

Resources