Creating multiple connectors via models in their own namespace? - ruby-on-rails

I have an application written in PHP using the ZendFramework, containing a library of "Connections", for example, MySQL, CSV, Twitter etc.
If a user signs up, they can connect to any data sources, say they pick a MySQL connector and a Twitter connector.
Based on the details they have entered in my UI, I would then connect to those datasources and retrieve the data they asked for.
I was hoping to set this up in Ruby on Rails but I'm not sure how. Basically what I want is:
#twitter_connection = Twitter.somefunction
#mysql_connection = Mysql.somefunction
The Twitter and MySQL models above would be in their own namespace. I called it "Connections" in my app. Can I have a namespace like that in Rails and store all the connection models in the /app/connections folder, so it would be:
/app/connections/mysql.rb
/app/connections/twitter.rb
Then, in those models, I would make the appropriate connection, whether it would be to MySQL, or an API like Twitter. Either way, the model would make the connection to the source and return whatever data I need.
Is that possible?
//Edit from comments
I have a class under '/app/connection/classname.rb'
The file contents are:
class Classname
def function
end
end
How do I access this class in a controller.
#variable = Classname.function doesn't work.

Related

Rails - Build adapter for several APIs

I need help on my thoughts on building an adapter for several APIs in Rails.
Let me explain first:
I want my clients to be able to add third-party extensions to my app.
I have a model Extension and another CustomExtension.
I create the extensions myself, that appear then to the "Available extensions" section. When a user clicks on "Add extension", it goes to the "My extensions" section (which is represented by CustomExtension).
I created an extension called API Connector and i want it to work as follows:
When a user clicks on "Add extension", he picks a category (that i have defined myself) the API is part of (like "Customer Reviews"). Then, the user will enter some fields like an api_key or an api_endpoint. Then, i want to be able to connect to this api and display some other fields relevant to the api (like the name of where it comes from, example: for Customer Reviews, if a user connects the Google API for it, i want to rename the extension from API Connector to Google Customer Reviews).
In a few words, I want to be able to connect several and different APIs with the same interface and let the user do it without implementing the API in my project.
EDIT — More info:
The APIs might not have the same authentication process or the same properties. They can be very different from each other.
The technical requirements are RESTful APIs and JSON-based.
As I understand it, you want to create a way for users to connect to APIs that are unknown until runtime, based on the parameters that a user defines? If so, there's a Ruby library (now removed from Rails) that's built for allowing easy connection to REST APIs, maybe that could be of help here?
https://github.com/rails/activeresource
So, suppose I want to pull breed info from the Cat API. Here's some example code that would let me define that at runtime:
require "active_resource"
require "ostruct"
##
# This is just a data-store. It could be an ActiveRecord object or some other set
# of values that you need for the API. You'll have to establish your own criteria
# for types of API configuration you can support
#config = OpenStruct.new(
# We need to set a custom header and value
header_name: 'x-api-key',
# get your own key here: https://docs.thecatapi.com
header_value: '96120fe6-0846-41c6-9a1d-8a70e691dd47',
base_url: "https://api.thecatapi.com/v1/",
# What's the path where this resource can be found
resource_name: "breeds",
# don't add ".json" to the URLs
use_json_extension: false,
)
##
# Create an anonymous class at runtime that inherits from ActiveResource::Base
#custom_extension = Class.new(ActiveResource::Base)
##
# Config our class based on the user-provided values.
#custom_extension.class_eval do
self.include_format_in_path = #config.use_json_extension
self.site = #config.base_url
self.headers[#config.header_name] = #config.header_value
self.element_name = #config.resource_name
# Log errors here
self.logger = Logger.new("./output.log")
end
puts #custom_extension.all.to_s
With any luck, that should download a list of cat breeds for you. Which should be enough to demonstrate the concept. The docs for ActiveResource can be found here: https://rubydoc.info/gems/activeresource
Be careful that you're not importing dangerous content from a source provided by a user!
Hopefully that's what you are looking for?

How to make a rails server wide object?

I am using the RedditKit gem and in order to access certain elements, I need to send a request to reddit api to create a "client" object. Below is my current logic:
## application_controller
before_action :redditkit_login
private
def redditkit_login
#client = RedditKit::Client.new ENV["reddit_username"], ENV["reddit_password"]
end
As you can see in my logic here, before EVERY REQUEST, I am subsequently making a new client object and then using that everywhere.
My question is, how do I only make one client object which can be used to serve ALL requests from anywhere?
My motive behind this is speed. For every request to server, I am making a new request to reddit and then responding to the original request. I want to have the client object readily available at all times.
You have a lot of options. A simple one would be to create a config/initializers/reddit_client.rb file and put in there:
RedditClient = RedditKit::Client.new ENV.fetch("reddit_username"), ENV("reddit_password")
(note I switched to ENV.fetch because it will error if the key is not found, which can be helpful).
You could also rename the file as app/models/reddit_client.rb. Although it's not really a model, that folder is also autoloaded so it should work as well.

Multi-tenant app with custom domains: how to populate tenant specific data in initializers and mailers?

I'm creating a multi-tenant app which uses Devise for authentication, which has an initializer file to set app specific information.
I'd also like to use the tenant's domain information in mailers.
What's the best way to store this information and populate it in the initializers and mailers?
You should not have tenant specific information including mailer information in file. Natural thing is to store information in database table. If you properly setup multi-tenant app, then database data for each tenant is completely separate from other tenants.
For example you could have table TenantInformation and put all tenant specific information like mailer connection string inside.
And depending of Rails verision you can set mailer connection option dinamicaly before sending email with :delivery_method_options check:
http://edgeguides.rubyonrails.org/action_mailer_basics.html
You can use existing solutions like https://github.com/influitive/apartment for easier work with tenants.
The best way I could come up with to properly include tenant subdomains in mailers and view links/urls is to monkey-patch url_for(which is internally used by other url helpers):
module ActionDispatch::Routing
class RouteSet
alias_method :original_url_for, :url_for
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
dynamic_options = Rails.application.config.respond_to?(:dynamic_url_options) ? Rails.application.config.dynamic_url_options.call : {}
options = options.merge(default_url_options).merge(dynamic_options)
original_url_for options, route_name, url_strategy
end
end
end
Put this in lib/dynamic_url_options.rb, then require 'dynamic_url_options' at the top of your environment file. You can then do:
config.dynamic_url_options = lambda {{
:subdomain => Apartment::Tenant.current
}}
If you're prefixing your tenant names with your environment, you'll have to do some additional stripping of the staging_ prefix within this lambda.

Where to store editable content?

I am building a Rails app that is intended to be eventually used by non-technical people. It consists of a few pages with blocks of text and a special page with interactive canvas drawings.
I want to allow them to easily edit any piece of text contained in the application. What are the best ways to achieve that? Currently, text is written in the different views of the application, which does not allow them to edit it without having to connect via FTP or similar and search for the right file.
I am thinking of three solutions:
Store all blocks of text in the database. On each page, fetch the requires blocks and insert them before rendering. Build a page that lists all blocks in the database in editable areas with a save button.
Store all blocks of text in a json file. Create a model that can read the file and fetch the blocks required by the views. Build a page that lets you edit each block and save it in the file.
Create some kind of password-protected admin interface that fetches all file in the views directory, use regexp to find blocks of text and allow the users to edit each block and save.
From my point of view, all of my three solutions look pretty bad. It does not feel okay to do so many calls to the database? Store your entire website text in a file? Parse HTML with regexps?
What are the usual approaches used to solve this problem?
There's a great book out there: Crafting Rails 4 Applications. Here's the link to source code from the book. You will find example in templater folder. Basically, you will be able to create custom templates based on the request parameters (just like Rails does).
Update. Here's a couple of links:
Default views in Rails 3.0 with custom resolvers by José Valim (author of the book, by the way).
Implementing a Rails 3 View Resolver.
Also, here's 5 coins from me. Basically, it works like this. You need to define your own resolver and connect it to your ApplicationController (or any other controller you want):
class Resolver < ActionView::Resolver
# some code here
end
class ApplicationController < ActionController::Base
append_view_path Resolver.new
end
During the rendering process, Rails will ask your controller's resolvers to provide a template (it will go through each of them, until it finds template or until there won't be any resolvers left). In order to provide template, your resolver needs a find_templates method:
def def find_templates(name, prefix, partial, details)
# some processing here
end
So, based on this method parameters, you're going to provide some database records. But even if you have some kind of model already, Rails expects this method to return ActionView::Template instance. It can be initialized like this:
ActionView::Template.new(source, identifier, handler, details)
So, that's how your find_templates should look like:
def find_templates(name, prefix, partial, details)
template = DatabaseTemplate.find... # your custom model for DB templates
ActionView::Template.new... # initializing actual template
end
Both model and resolver in detail are presented in the book's source code (templater/3_final/app/models/sql_template.rb).
I have done that a couple times with awesome user satisfaction by using this:
http://jejacks0n.github.io/mercury/
There is also a Railscast available which gives you a good overview and step by step instructions:
http://railscasts.com/episodes/296-mercury-editor
Hope it helps. It looks good and is easy to use for end users.

Specific Ruby on Rails routes deliema

Currently developing a RoR mobile web application for displaying information about particular places.
Let's call these places 'installations'. Each installation has at least one 'venue', which is a specific instance of the installation. So for example an installation could be a city park, and one of its corresponding venues could be the park during a concert or event. If this example is confusing, disregard, it doesn't matter much.
The data for these installations and their corresponding venues is hosted on Amazon Web Service S3 as json objects. I use HTTParty to read in the AWS S3 json objects. I am currently reading them in like so:
In the application controller I have:
inlcude HTTParty
base_uri 's3.amazonaws.com/our_bucket'
before_filter :set_up_httparty
def set_up_httparty
#installation = "INSTALLATION"
#venue = "VENUE"
#dir_url = "/#{#installation}/#{#venue}/"
end
In my corresponding controllers, where I get separate information I have:
response =
ApplicationController.get("#{#dir_url}/ConstantUniqueName.json")
Currently I am hardcoding INSTALLATION and VENUE values to point to a specific set of folders. This works great, but I need to be able to take in these values from the url like so:
www.themobilewebapp.com/INSTALLATION/VENUE/index
Now I am sure it is most likely possibly to pass in these values with params like so:
www.themobilewebapp.com/index?installtion=INSTALLATION&venue=VENUE
But if possible I would like to set my URL's up the previous way. I need to have the URL's be friendly for users to put in themselves and have QRC codes point directly to a specific installation and corresponding venue.
If not possible to be able to do something like www.mobwebapp.com/INSTALL/VEN/index then is it possible to set up sub domains for each venue and then pull in that venue as a string?
Any help is appreciated!! Thanks!
If you put this in your config/routes.rb file then you will be able to use the URL pattern that you want:
match ':installation/:venue/index', :controller => :venue, :action => :index

Resources