I am currently coding an application in Ruby that does some simple external API calls to Soundcloud's API.
I have developed a bunch of code inside a single .rb file and want to put this into the rails architecture. This Ruby file has the following classes:
class SoundcloudUser
class SoundcloudQuery
class SoundcloudFollowers
Currently I understand that I can put these classes into seperate .rb files, and then just put them into the /models/ folder which then gives me the ability to call these classes from elsewhere in my rails application (using require/include).
My question is simply, is this the correct way to go about this? I am familiar with rails, but I am new to transferring a Ruby developed project into the rails format. I tried searching best practices for this in the Ruby style guide but I didn't really find anything.
On a side note - I wanted to also create another class that acts as a ?service? wherein in checks my local database if an entry already exists in the database, and if not, then it will query new data. My side-question here would be similar - where would this .rb file for this 'service' live?
I hope I explained my question clearly enough, if not, I am happy to add some clarifications. Thank you for your time!
If in Rails, you can put them in either lib/ or somewhere in the main app directory. For example, you can create app/services and put them inside there, and when you restart the Rails server you should be able to call SoundcloudUser (provided you name them app/services/soundcloud_user.rb.
I always look at the Gitlab source code for this. It's a gigantic Rails app but look at this file: https://github.com/gitlabhq/gitlabhq/blob/master/app/services/gravatar_service.rb. Because it's inside an app/services (any name actually), GravatarService can be called from anywhere in Rails. If you want to have some namespacing, you have to put it in app/services/soundcloud/user.rb or lib/soundcloud/user.rb and name the class Soundcloud::User.
For the class that acts as a service, it seems like it orchestrates the logic of "check if (song?) exists, else scrape. Some people put it in a model class, I'd probably put it in a service class a la the Gitlab source code. Hope I helped.
Related
I am working on a project where the current developers have put their "Plain Old Ruby Objects" in the models directory of our Rails app.
I have seen most examples online where the PORO files go inside lib instead, but some say models.
Is there even a logical / specific reason why people put them in the models directory over the lib directory?
"Idiomatically" the models directory intended for code used to hold state. Most of the time this would be ActiveRecord subclasses corresponding to database tables. However frequently people put other stuff in the models directory. One thing often seen are code dropped here in order to take advantage of auto-reloading. (the lib dir doesn't normally auto-reload)
Based on the Getting Started Rails guide, the app/models/ directory is pretty much anything, whereas lib/ is for modules that are used across the entire app (e.g. extensions).
As #seand said, yes, one advantage is that the app/models/ directory automatically reloads, but I tend to think of it as any class that "interacts with other classes" should live in app/models/, with the only exception being a service class (which I tend to think of as "a class which manipulates the state of another class"), which I tend to put into app/services/.
I know a lot of developers would disagree with me - many I've talked to even create a separate directory namespaced to their app (e.g. if your app is named "MyBlog", they would create an app/myblog directory for any object not explicitly backed by the database, but not a module or a service class either.
That said, I think ultimately it boils down to a) personal preference and b) where you feel is best to place the PORO with respect to your app.
There is no hard and fast rule on where to put POROs. The rails community has been hashing this out for a while now. At one point the convention was to put stuff in the concerns directory but that seems to have fallen out of favor with some folks.
One rule of thumb for the difference between /lib and app/{blah} is that code in the /lib folder is code that you presumably can reuse across several projects e.g. general purpose class or utilities. for example if you have some custom monkey patches to core ruby or rails classes that you will use in multiple projects, a good place to but them would be in the lib folder. Anything in app/{blah} should pertain specifically to current project.
One way to think of lib folder is as the poor cousin of plugins and gems.
Just my 2 cents on the subject
How would you structure a simple Sinatra app?
I'm making it right now and I want the app to have these features:
The "app" is more of an admin dashboard for all the information inside it. Then another app will access the information via REST. I have not created the dashboard yet, just the getting of things from the database
Sessions and authentication (have not implemented this yet)
You can upload pictures, and other the other app can display those pictures
I have created a testing file using RSpec
Reports generation via Prawn
Currently the setup is just this:
app.rb
test_app.rb
because I have literally just the app and testing file. So far I have used Datamapper for the ORM, SQLite for the database. This is my first Ruby/Sinatra project, so any and all advice is welcome - what other libraries should I be using, should I put stuff like config.ru, etc.
Sinatra is not opinionated when it comes to your file structure, you can place files however you like. When I first started I just dropped everything in the top level, but over time reading how people structure their code, reading over the source code of gems I've broken up my code into smaller .rb files that fulfill a specific function and places all of them under /lib, it's a convention carried over from rails perhaps but does not have any of the magic associated with it in rails. If you use scss or coffee script they depend on certain folders to exist, you will discover for yourself over time (and even then you can reconfigure them however you wish) and from this you will figure out what works best for you.
if you write a restful api, check out grape - https://github.com/intridea/grape
you will also find sinatra-contrib to be very useful - https://github.com/sinatra/sinatra-contrib
As for what to do with your config.ru - https://github.com/rack/rack/wiki/%28tutorial%29-rackup-howto
I'm making a gem that will add some custom responders to an application's controllers. To test this, I'm going to need a dummy application sitting inside of a test directory that I can load and somehow generate views from.
I'd prefer to use Cucumber to test this gem, because that is what I'm most comfortable with having used it in the past.
How do I generate an application inside of my test directory like this? I will need at least a controller and a model, but views aren't necessary (the responder is only for JSON). Can I just generate a new Rails app within /features/support/dummy? How would I run the dummy application from within my test suite?
At first, do not generate anything within features/support/. That's the place for global hooks.
Your problem sounds not hard if I understood correctly. Here is my proposed steps.
Create a demo directory in project root. New demo app will be under it.
Create a ruby module/class under features/support/, with methods to generate a demo app and delete it. The demo app will be simply some directories like app/contorllers for test purpose. Making a whole new Rails app sounds overkill.
Create a tag for the Scenario which need generate app. Add Before and After hook for this tag to add and remove app for this Scenario, by calling the module/class in #2
I have a question regarding how to call ruby classes that reside outside of rails app structure.
I have few Ruby classes that are used/invoked from cron job periodically.
I would like to use the same ruby classes to be invoked from a rails controller
after user creates a model object.
Is it possible to invoke code that resides outside of rails app directory without copying the ruby classes
over. I am mostly concerned that both the classes will be out of sync soon if I have to copy them to rails app folder.
Ruby app reside in, /usr/local/railsapp1 . The ruby classes reside in /usr/local/other_task/
Any suggestions would be of great help.
thanks
You can. Just use in your config/environment.rb
config.load_paths << "/usr/local/other_task/"
This will load whatever classes in that folder into your rails environment.
But the path is hard-coded in this case, so you have to be careful when deploying.
I'm attempting to reopen the String class in rails and add a bunch more methods for my app to use. Writing the code isn't a problem - my question is rather about where this code should go.
It doesn't make sense to me to reopen a class inside a different model file, because it really has nothing to do with any of the models specifically. I thought perhaps somewhere in config or lib would make sense, but I'm not particularly well versed with RoR yet.
To summarize, where would be the most logical place to define class-modifying code, and are there any implications depending on where/when the code is loaded?
The most logical place is probably in a file in the config/initializers directory. Any *.rb file you put in here will be automatically executed when rails boots. If you want, you could put them in a sub folder, so you could do something like config/initializers/extensions/*.rb.
I try keep these monkey-patches to a minimum, only when they are very clearly in the best interest of my code.
Lately I have preferred to keep the files organized in folders such as lib/monkey/string.rb, lib/monkey/hash.rb, etc. I then require all files in the lib/monkey folder in my environment.rb file.
# Load all monkey-patches.
Dir["lib/monkey/*.rb"].each {|monkeyfile| require monkeyfile}
This keeps all of my class modifying code isolated to one location, should a problem arise. I also enjoy the somewhat goofy naming, because it makes it stand out as something to be mindful of. Someone may have a better system, if so ... I'd love to hear about it!