How to check where currently used controller inherits from? - ruby-on-rails

In my Rails 7 application I've got two controllers:
class Context::FrontendController < ApplicationController
end
class Context::BackendController < ApplicationController
end
All my other controllers (and there are a lot of them) inherit from either the first one or the second one (but never both).
In my views I sometimes need to show or hide certain elements depending on if the current controller inherits from the FrontendController OR the BackendController.
How can this check be done?

In my views I sometimes need to show or hide certain elements depending on if the current controller inherits from the FrontendController OR the BackendController.
How can this check be done?
You can do this check (as shown by #mechnicov), but you shouldn't. Instead, use OOP.
class ApplicationController
def current_area
# raise NotImplementedError
:none
end
helper_method :current_area
end
class FrontendController < ApplicationController
def current_area
:frontend
end
end
class BackendController < ApplicationController
def current_area
:backend
end
end
Then
<% if current_area == :frontend %>
You can prettify this as you wish (make methods frontend? / backend?, etc.)

In your view you can use something like
<% if controller.class.ancestors.include?(Context::BackendController) %>
<%= show.some.content %>
<% end %>
May be create some helper
def inherited_from?(controller_class)
controller.class.ancestors.include?(controller_class)
end
And then
<% if inherited_from?(Context::BackendController) %>
<%= show.some.content %>
<% end %>

Related

What is the Rails way of handling edits made to a resource's ActiveStorage attachment(s)?

I'm trying out ActiveStorage for the first time and wondering what the convention is for controller code used to purge some or all of a resource's attached files?
Two solutions I can see, and hate:
A designated controller just for managing attachments (which would omit any kind of resource specific callbacks)
In each resource controller add some kind of logic to the destroy methods
What is the Rails way of handling edits made to a resource's ActiveStorage attachment(s)?
I’d choose the first solution you considered:
A designated controller just for managing attachments (which would omit any kind of resource specific callbacks
This is roughly what we do in Basecamp. Here’s a demo:
# app/models/event.rb
class Event < ApplicationRecord
belongs_to :user
has_many_attached :highlights
end
# app/controllers/events/highlights_controller.rb
class Events::HighlightsController < ApplicationController
before_action :set_event, :set_highlight
def destroy
#highlight.purge_later
redirect_to #event
end
private
def set_event
#event = Current.user.events.find(params[:event_id])
end
def set_highlight
#highlight = #event.highlights.find(params[:id])
end
end
# config/routes.rb
Rails.application.routes.draw do
resources :events do
resources :highlights, controller: "events/highlights"
end
end
<%# app/views/events/show.html.erb %>
<% #event.highlights.each do |highlight| %>
<%= link_to image_tag(highlight.representation(resize: "200x200>")), highlight %><br>
<%= link_to "Delete this highlight", event_highlight_path(#event, highlight), method: :delete %>
<% end %>

How do I tell if the current action is in an Engine?

Within my application.html.erb, I want to be able to detect if the currently rendering page is from within a mounted engine (Forem, if that matters), so that I can add an active class to the nav bar. Is there an easy way to detect this?
I'm using Rails 3.2.
You could add a helper method in Forem::ApplicationController by reopening the class:
Forem::ApplicationController.class_eval do
def forem?
true
end
helper_method :forem?
end
Add the above file in app/decorators/forem/application_controller_decorator.rb for example.
This way every time a view is rendered by Forem's controller you would be able to call forem? within your view.
application.html.erb
<% if forem? %>
# do something
<% end %>
You might want to check if the current instance respond_to?(:forem?) first, or add a forem? method returning false in your own application_controller.rb.
A very similar approach can be done without the use of decorator loading (just using Rails default loading), e.g. for Thredded:
#This file would be at app/controllers/thredded/application_controller.rb in your main_app repo
require_dependency File.expand_path("../../app/controllers/thredded/application_controller",
Thredded::Engine.called_from)
module Thredded
class ApplicationController < ::ApplicationController
def thredded?
true
end
end
end
and then add the default value and helper_method declaration in your own ApplicationController:
class ApplicationController < ActionController::Base
helper_method :thredded?
def thredded?
false
end
# etc
end
You can use this:
<% if controller.controller_name == ""something" &&
controller.action_name == "something" %>
Do someting <!-- add you class -->
<% end %>

access application controller in view rails

I am having a action in application controller
def is_customer_logged_in?
!!session[:customer_id]
end
And in my view am trying to access the application_controller action like this
<% unless is_customer_logged_in? %>
some functions
<% end %>
The above code is a partial layouts.
This is the error message I am facing
undefined method `is_customer_logged_in?' for #<#<Class:0xb51a5300>:0xb5616484>
You can define it to be a helper method and you should be able to access that method in the view.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def is_customer_logged_in?
!!session[:customer_id]
end
helper_method :is_customer_logged_in?
end
try helper_method: is_customer_logged_in?

How do I put API data into a model?

Currently I am using the Last.fm api to return concert data (returns a hash) in my controller, and in the view cycling through this hash to return the data I want. I want this concert data to become more dynamic and put everything into a model. How do I do this? Should I do this in the controller or somehow in the model?
Here is an example of my code
# app/controllers/events_controller.rb
class EventsController < ApplicationController
def index
#events = #lastfm.geo.get_events("Chicago",0,5)
respond_with #events
end
end
# app/views/events/index.html.erb
<% #events.each do |event| %>
Headliner: <%= event["artists"]["headliner"] %>
<% end %>
In this example I would would want and Event Model with headliner as a parameter, and put all 5 of the events into this model.
I believe it's a good idea to have a model. There are several advantages as I can see
1 - You could access data as OO way as other objects
2 - if you have some business logics (Ex: calculations) you could do it in the model itself with out messing up your view
3 - it's clean and DRY
Example model class would be (this is not a working model, but just to give you an idea):
class Event
attr_accessor :headliner
def self.event_list(limit = 5)
lastfm.geo.get_events("Chicago",0,limit)
end
end
So you can clean-up your view as
<% Event.each do |event| %>
Headliner: event.headliner
<% end %>
It's difficult to thoroughly answer this question without more knowledge about the last.fm API. As a general rule, you want to keep most of your complex logic and relationship data in the model.
For example, you already know you need an Event model, but it also looks like you might need an Artist model as well. You might end up with something like this:
# app/models/artist.rb
class Artist
attr_accessor :name
def initialize(name)
self.name = name
end
end
# app/models/event.rb
class Event
attr_accessor :artists
def initialize(attributes)
#attributes = attributes
self.artists = attributes['artists'].map do |artist_name|
Artist.new(artist_name)
end
end
def headliner
#headliner ||= self.artists.detect do |artist|
#attributes['headliner'] == artist.name
end
end
end
# app/controllers/events_controller.rb
class EventsController < ApplicationController
def index
#events = #lastfm.geo.get_events('Chicago', 0, 5).map do |event_attributes|
Event.new(event_attributes)
end
respond_with #events
end
end
You might also want to look into ActiveModel, which has some helpful features for models that aren't database-backed and can't inherit from ActiveRecord::Base.

rails: how do i access a method in my application controller?

Noob scoping issue, I imagine. :\
class ApplicationController < ActionController::Base
protect_from_forgery
#locations = get_locations
def get_locations
Location.where(:active => true).order('name').all
end
end
Error:
undefined local variable or method `get_locations' for ApplicationController:Class
Two questions:
1) What's with the error? Am I calling the method incorrectly?
2) How do I access this method from a sub-classed controller?
You're calling get_locations within the class scope, but the method is an instance method, not a class method. If for example you used def self.get_locations then you would be providing a class method, one of which you can use within the class scope (after you have defined it, not before like you're doing).
The problem here is the logic, what is this method for? What do you intend to use #locations for? If it's to go inside your application view, then you should put this method into the ApplicationHelper module, and call it from inside the relevant action. If you'd like it in another view on another controller and you'd like to use #locations inside your locations method, perhaps your setup might look something like this:
PagesController
class PagesController < ActionController::Base
def locations
#locations = Location.where(:active => true).order('name').all
end
end
locations.html.erb
<% #locations.each do |location| %>
<%= # do something with 'location' %>
<% end %>
If you'd like to use this inside of your application.html.erb you can simplify it quite some..
ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery
def locations
Location.where(:active => true).order('name').all
end
end
application.html.erb
<% locations.each do |location| %>
<%= # do something with location %>
<% end %>
The answer boils down to logic, and to really figure out exactly what you're looking for, more details would probably be required.
You're calling it from the class scope, not from an instance scope. more likely what you want is the following:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :setup_locations
private
def setup_locations
#locations = Location.where(:active => true).order('name').all
end
end
To make your original example work, you'd need to make #get_locations defined on self (which points to the class at definition), like so:
class ApplicationController < ActionController::Base
protect_from_forgery
#locations = get_locations
def self.get_locations
Location.where(:active => true).order('name').all
end
end
The problem with that code is that #locations will only be available from the class level as a class instance variable, which is comparable to a static variable in most other languages, and which probably isn't what you want.
I imagine that this line:
#locations = get_locations
... is trying to access the class level method get_locations and not the instance method.
The clue here is that the error message is showing that it can't find it on the class itself (ApplicationController:Class) and not an instance of that class. That means that you're in the class scope, not instance scope.
This would fix it:
def self.get_locations
Location.where(:active => true).order('name').all
end
Even the question is quite old, you can also call your controller action anywhere just by calling:
ApplicationController.new.get_locations

Resources