I have a sidebar that will rotate its content based on where the user is (amongst others; in reality also on who the user is, how far her profile is finished and so on).
What I want is a helper that checks against the controller, action and id of the current page.
if the controller is JobsController and the action is show or index, use partial _sidebar_add_your_job.
if the controller is UsersController and the action is show or index, use partial _sidebar_add_your_cv.
The simplified version of my helper, in app/helpers/sidebar_helper.rb is:
module SidebarHelper
def sidebar_partial
if partial
return "sidebar_#{partial}"
end
end
# Determines what sidebar partial to render.
def partial
partial = nil
if ((section == :jobseekers) && current_user.nil?)
partial = :add_cv
elsif ((section == :employers) && current_user.nil?)
partial = :add_job
end
partial
end
def section url = nil
url = request.fullpath if url.nil?
section = nil
if (url == root_path || url.match(/^\/jobs/) )
section = :jobseekers
elsif (url.match(/^\/employer/) || url.match(/\/users\/[a-z0-9]+/) )
section = :employers
end
section
end
end
Especially the last part, where I match regular expresssions against urls is ugly and fails for quite a few cases. Most notably: users/sign_in, users/sign_up` and such. I am relucatant to start maintaining an entire blacklist of these exceptions, it feels too ugly and too tightly coupled to the routes.
How can I best achieve some conditional partial inclusion based on the URL, or controller&action and -in future- on a few more simple conditions such as the role and status of the current user?
How can I test against Controller and its action of the current page/request in a helper?
Please check this post there you can find an easy way to make current controller and action available in your views
Related
In the shop's customer section I would like to render the user account menu (which we can see by default when reaching /my-account URL) as a side column on some others controllers like the ones associated to "/my-adresses", "/identity" pages ..
I thought I would have to create another controller which purpose would be to gather menu infos and only render the menu <ul> list. Then I could override Controllers such as MyAccountController, IdentityController to include this former Ctrl and then render its content as part of the views of those two other controllers views.
So how one can load a specific controller from another in order to render shared views between pages ? Which is the right/clean way to do that ?
I heard about $this->getController() but I did not find any snippet or implementation of what I'd like to achieve. I new to Prestashop but even if the code seems clear, I don't get the point here.
Thank you !
After getting a bit deeper into sources, I ended up moving the menu (initially part of the MyAccountControllerCore alias my-account template) into a brand new Controller "MyAccountMenuController", in /override/controllers/front/.
<?php
// In /override/controllers/front/MyAccountMenuController.php
// The "exposer" controller
public function display()
{
// Do what ever you want to pass specific variables
if (! $this->template) {
throw new Exception(get_class($this) . '::display() : missing template.');
}
$this->context->smarty->display($this->template);
return true;
}
I am now able to import this menu by adding the following snippet inside the initContent() method of each controller that are part of the customer account section (this means that each of them must be overridden, for more info about overriding controllers, see documentation):
<?php
// In /override/controllers/front/MyAccountController.php
// The "consumer" controller
public function initContent() {
// ...
// Importing the customer area's menu
$menuController = $this->getController('MyAccountMenuController');
ob_start();
$menuController->run();
$this->context->smarty->assign('myAccountMenu', ob_get_clean());
}
I don't think the original purpose of getController method (located in ControllerCore class) was meant to include another controller output, at least in Prestashop 1.5. Still, to me this approach is far cleaner than duplicate views code.
If you have a better (cleaner) approach to implement such a mechanism, please let me know !
Any thoughts ?
Given a model Post that has_many attachments, and an attachment has a hidden flag. Throughout the app I want to easily say post.attachments and only get the visible ones, so i setup a default scope in the Attachment model (using squeel):
default_scope -> { where { (hidden != true) | (hidden == nil) } }
But the admin page needs to be able to see all attachments for a post, not just the visible ones (so you can toggle the hidden checkbox). The default way of doing this (in admin/posts.rb) uses the default_scope and only lets me edit the visible ones:
f.has_many :attachments do |a|
...
end
I know I could just not use default_scope and instead name it :visible, and then everywhere (except the admin page) say post.attachments.visible but I prefer not having the do that.
How can I unscope the children attachments on the admin page?
Here's the solution I worked out:
In app/admin/posts.rb
f.has_many :attachments, for: [:attachments, f.object.attachments_including_hidden] do |a|
...
end
And in app/models/posts.rb
def attachments_including_hidden
Attachment.unscoped.where( attachable_id: id )
end
(where Attachment model belongs_to: :attachable, polymorphic: true )
What's going on? ActiveAdmin uses Formtastic, which uses Rails Form Builder.
The form.has_many method is an ActiveAdmin method, which calls Formtastic's form.inputs, which in turn calls Rails' fields_for. The :for option will get passed all the way down the fields_for, which can take a collection (as its 2nd arg) so I deliver this collection to it explicitly.
I'm creating a custom SimpleForm input. It utilizes a javascript modal popup to select values.
I can basically get it to work if I include the modal partial in the form view, but I would ideally like to have the custom input push the partial to the template.
However, I can't get it to work. I'm trying this, but it doesn't render the partial correctly.
class ProductCategoryImageSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input
html = ''
html << 'Launch demo modal'
File.open("#{Rails.root}/app/views/product_categories/_browse_modal.html.erb", 'r') do |f|
html << f.read
end
end
end
Any thoughts?
EDIT
I'm apparently too new of a user to post screenshots, but here are links to the differences in functionality:
When I embed the modal code in the form, I get this, which is the desired functionality:
working
When I try to put the modal code in the custom input, I get this instead:
not working
You can also render partial from a custom input using the SimpleForm::FormBuilder instance which is assigned to an instance variable named #builder:
class ProductCategoryImageSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input
#builder.template.render(partial: 'product_categories/browse_modal', locals: { foo: 'bar'})
end
end
Weirdly, it seems I've already answered it here.
Does this work for you?
ERB.new(f.read).result(binding)
PS: Updated with ERB instead of HAML.
I have tried to do it from the controller and from the active admin override controller and I can't make it work.
A user creates a website.
current_user has an id attribute
website has an user_id attribute
So when I create a new website I want to add the current_user.id into website.user_id. I can't.
Anybody know how?
Right now I need it on the new/create actions but I'll probably need this on the edit/update actions too.
This seems to work for me:
ActiveAdmin.register Website do
controller do
# Do some custom stuff on GET /admin/websites/*/edit
def edit
super do |format|
# Do what you want here ...
#website.user = current_user
end
end
end
end
You should be able to override other controller actions in the same way.
ActiveAdmin.register Model do
# also look in to before_create if hidden on form
before_build do |record|
record.user = current_user
end
end
See https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/resource_dsl.rb#L156
You need to add a 'new' method to the controller. The 'new' method creates an empty website object that will be passed to the form. The default 'new' method just creates an empty #website object. Your 'new' method should create the empty object, and then initialize the value of user to current user:
ActiveAdmin.register Website do
controller do
# Custom new method
def new
#website = Website.new
#website.user = current_user
#set any other values you might want to initialize
end
end
I need to render some views without layout.
To skip line :render :layout=>false and if else logic from controller actions,
i have custom mime type like phtml (plain html).
Mime::Type.register "text/phtml", :phtml
this format need to render the same html views, but only without layout. I complete this with this chunk of code in app. controller:
before_filter proc { |controller|
if params[:format] && params[:format]=='phtml'
controller.action_has_layout = false
controller.request.format = 'html'
end
}
First, this is ugly, second i can't any more control this format from controller in the way:
respond_to :phtml,:only=>:index
because it will always render view with requested format phtml.
is there a better solution? example? how can i alias view formats?
Thank a lot
You can use the layout method in your controller directly:
class ProductsController < ApplicationController
layout "product", :except => [:index, :rss]
end
Or to use no layout at all:
class ProductsController < ApplicationController
layout nil
end
Check out the guide for more info.
I haven't found better solution,only update to my previous example:
before_filter proc { |controller|
if params[:format] && params[:format]=='plain_html' && controller.collect_mimes_from_class_level.include?(:plain_html)
controller.action_has_layout = false
controller.request.format = 'html'
end
}
i added this line to check is a new format defined into our controller:
controller.collect_mimes_from_class_level.include?(:plain_html)
Now we can have full new format which will render our standard html vews rather the build new views for the new format.
This can be useful if we wont to share existing html code, but build different logic based on requested format.
For example, we can easily prepare our html content for print like:
class PagesController < ActionController::Base
layout 'print',:only=>:show
respond_to :plain_html,:only=>[:show]
def show
Page.find(1)
respond_with #page
end
end
And request will be like:
http://www.example.com/pages/1.plain_html
I hope that someone will find this useful.
If u have a better approach for doing this, please share with us.
Regards