Rails: Mimic relations in tableless activerecord - ruby-on-rails

I'm using the BaseWithoutTable plugin to extend ActiveRecord. This allows me to create models without underlying tables (I'm getting data from a webservice). I would like my web application to remain restful, however i'm stumped on how to do that without relations.
To be more concrete, let's say I have a book model and an author model and I get both resources from a web service. I would like to access book resources like /authors/1/books.
It seems there could be two routes I could choose. First, hack the relations (belongs_to, has_many) so that I can define my own without the need for foreign keys. Second, I could possibly build custom routes and controller methods that allow me to access the previous url.
If anyone has any thoughts on how to do this I would much appreciate it.
Thanks and let me know if you need more info.

For the url given you could do the something like the following.
/authors/1/books
class Books < ApplicationController
before :find_author
def show
#books = Books.get_from_web_service_for_author(#author)
end
def find_author
#author = params[:author_id]
end
end
You would need to define the method for accessing your webservice and also have a nested resource defined in your routes.

Related

Unable to change the parameter from id to a custom variable in Rails

I've been racking my brain trying to figure out something that should be extremely simple, so I'm sure I'm just overlooking something and a fresh set of eyes might be useful since all my code is seemingly blurring together. I'm attempting to create vanity URLS for a site that allows users to create categories and then post relevant stories based on those categories. So, for example, I would like users to access /categories/movies in order to view the movie section. If I set it up to use the category id, /categories/1, it works no problem. For whatever reason, rails keeps trying to use the id parameter to find the category as opposed to the title parameter. I'm using Ruby 2.0.0 and Rails 4.0. I've read that the "find_by" method will become deprecated soon, so if there's a better way to handle this, that'd be great. Here's the relevant code:
Categories Controller
def show
#categories = Category.find_by_title(params[:title])
#category = Category.find_by_title(params[:title])
#posts = Post.where(category: set_category).all
end
Routes.rb
resources :categories
get "/categories/:title" => "categories#show"
Terminal readout when rendering page
Processing by CategoriesController#show as HTML
Parameters: {"id"=>"Movies"}
Just to reiterate, the parameters should read {"title"=>"Movies"} not id. Like I said, I'm sure it's something extremely simple that I've overlooked. Any help would be appreciated. Thanks.
I had to implement vanity urls as well and followed this blog post/tutorial
You pretty much create a slug in your model with the vanity-url, so
class Category < ActiveRecord::Base
def slug
title.downcase.gsub(" ", "-")
end
def to_param
"#{slug}"
end
end
Your show action in your controller would use the find_by_slug method
I think there is a gem that does this as well called friendly_id and here is a railscast but I have not personally used it
Hope this helps

How can I insert this subdomain filtering in an existing Rails application?

I have an existing Rails 3.2 application that is basically a simple product catalog. Now I am faced with a situation where I need to only allow interactions with specific products based on the subdomain the user is using to access the site.
The Product model belongs_to a Repository, which has the subdomain as a value.
So that a request to:
http://bobs_store.myapp.com/products
only shows products that have a repository with the name bobs_store.
Where is/are the best place/places to introduce this filtering? Is there some kind of default scope I can create at the model level to do this? My only problem with that is that I can't access the request from the model, so does this mean that I have to pass the subdomain in to every call I make to that model?
One other thing, all of the calls to the Product model are made like this:
current_user.products.<whatever>
Is it possible to modify my current_user helper method somehow to get my desired functionality? Barring that, is there something fancy I can do with routes? These are shots in the dark, but I'm hoping there is some Rails shortcut I can use that I'm not aware of.
As luri G mentioned, watch this Railscast:
221-Subdomains
Create a scope to query products of a repository
class Product < ActiveRecord::Base
belongs_to :repository
scope :for_repository,
(lambda do |repository_name|
includes(:repository).
merge(Repository.where(name: repository_name))
end)
end
After you had implemented the subdomain route handling logic as per the Railscasts, in your controller you will call the products for a repository like this:
current_user.products.for_repository(request.subdomain)
The way I've seen it done before is to have a scope on the model, e.g. Product.repository_scope.
class Product < ActiveRecord::Base
def self.repository_scope(repository)
where(repository: repository)
end
end
I'm not sure about a good workaround for not having to pass in the current repository every time.

Rails global variable

Im using bootstrap & rails and have a user model and post model..users create posts (collections)..
with bootstrap in the navbar i want the user to be able to click a dropdown which displays the name's of their posts..i did this on one controller with a private method and a before_action but i don't want to do this for all the controllers and it didn't work for the application controller...
is there a better way to do this??
I was doing this
def list
#user = User.find_by_username(params[:id])
#collections = #user.collections
end
and a
before_action :list
at the top of the controller
What's the most semantic way to accomplish this??
If you could move both to your application controller, then it would be available to any controller. More generally, I'm not sure if this is the best approach to solve your problem.
These tips might also be useful.
Are you using devise? Or some other authentication plugin? If so you're likely going to have a current_user helper. This would allow you to simply do #collections = current_user.collections
To the extent possible, I recommend using more descriptive names for your actions and parameters. def fetch_list_collections might be a better name or instead of passing a param named id, perhaps your param should be named username. These naming conventions become extremely important both for others who might look at your code as well as for yourself if you return to it and are trying to remember what you wrote N months ago.
Your list action is generating a N+1 queries. Meaning that you're hitting the database multiple times when you should do so just once. See the rails guide on this. You might also look at ways to avoid this w/ devise. Devise is pretty well documented and I'll bet there is something in the wiki discussing this.
You may want to consider limiting when you call this action - at a minimum - a post request to an update action? What about before they've logged in? current_user might be nil and you'd have an error attempting to call a collections method on nil.
Take your time learning this stuff. You don't have to learn it all at once, but I thought the above might be helpful.
I got it to work with this in the application controller
before_action :list
private
def list
#collections = current_user.collections
end
thanks #arieljuod

In Rails filter all ActiveRecord calls

I have a rail app which is meant for users from different Organizations.
I want to make a mechanism that will make sure that when a user gets any data from the db, it can be only from his organization.
I want that to be true even if there is a bug in my queries i.e. I want this filter to be independent of all other code.
How can I implement this filter to run on all ActiveRecord calls?
can I use "default_scope" (http://apidock.com/rails/ActiveRecord/Scoping/Default/ClassMethods/default_scope) for that but apply it to all models some how?
Thank you!
For me the only way to achieve that properly is by scoping all your methods to something like
user_organization.<relation>.<query>
You can for example have a user_organization method in your ApplicationController
class ApplicationController < ActionController::Base
def user_organization
current_user.organization
end
end
The default scope does not accept parameters if I'm not wrong, and I highly discourage you using for anything.

Using multiple controllers in one view in Rails

I'm working on something like a social networking mesh; I am using different API's from various websites, e.g. Last.FM, Delicious, Twitter, ...
I've created one controller per each website (currently, there are 7).
Sample views:
localhost:3000/lastfm <- All datas i gathered from user's Last.fm account
localhost:3000/twitter <- All datas i gathered from user's Twitter account
...
Now I want to show these datas in one view (localhost:3000/index.hmtl) by using these different controllers.
Components are deprecated, creating one controller and bury all the API's in that seems ugly, too..
So I don't know how to do this. Any idea?
First off, you should put all of the data-storing and data-gathering methods into Resources and Models so they are accessible from all controllers. You can keep the internal data-mutating operations in your individual controllers though. Once you have it organized like this, you could do what Hobo does: create a controller just for the front page, "front_controller" if you will. Here you can display data gathered from all of your models and resources, as well as links to your other controller actions.
These are a few interesting thoughts on better organizing your models and controllers (fat models, skinny controllers is a rule of thumb.
Since you said you are using other API's (like lastfm and twitter), you might want to take a look at this railscasts about creating non ActiveRecord models (models that are not tied to a database)
here is some pseudo code, keep in mind its really only targeted at your question.
# pseudo code
class TwitterController < ApplicationController
def index
#services = {
:twitter => TwitterModel.find(:all, ...),
}
end
def update_twitter
TwitterUpdaterClass.update { |twit|
_m = TwitterModel.new
_m.message = twit.msg
_m.from = twit.from
# ..
_m.save
}
end
end
class MyIndexController < ApplicationController
def index
#services = {
:twitter => TwitterModel.find(:all, ...),
:lastfm => LastFmModel.find(:all, ...)
}
end
end
it might be much better to have background-workers update your rest-services instead a controller which you need to invoke every time you want to fetch recent tweets.
here is nice article showing - 6 ways to run background jobs in rubyonrails
# more pseudo code
class TwitterWorker < BackgrounDRb::MetaWorker
set_worker_name :twitter_worker
def create(args = nil) # instead of TwitterController.update_twitter
TwitterUpdaterClass.update { |twit|
_m = TwitterModel.new
_m.message = twit.msg
_m.from = twit.from
# ..
_m.save
}
end
end
First off, you should put all of the data-storing and data-gathering methods into Resources and Models so they are accessible from all controllers. You can keep the internal data-mutating operations in your individual controllers though. Once you have it organized like this, you could do what Hobo does: create a controller just for the front page, "front_controller" if you will. Here you can display data gathered from all of your models and resources, as well as links to your other controller actions.
I think you should read a bit about rails' MVC architecture.
It seems to me that you are neglecting the M(odel) part of it. The models should hold the data, thus being the most important part of your application.These are a few interesting thoughts on better organizing your models and controllers (fat models, skinny controllers is a rule of thumb. Since you said you are using other API's (like lastfm and twitter), you might want to take a look at this railscast about creating non ActiveRecord models (models that are not tied to a database)
If you also provide an API for your users, I suggest using a RESTful approach, as it can really be easy to develop and maintain once you get the hang of it. You should read more about resources, as your localhost/lastfm and localhost/twitter are resources and not views.
Hope this helps. Good luck

Resources