How do you unregister a model in wagtail modeladmin? - django-admin

I need to do the equivalent of... 'admin.site.unregister(Value)' but for a model registered with wagtailmodeladmin using 'modeladmin_register(Value)' in wagtail_hooks.py. How do you do that?

No built-in way to do it, but if you wanted to add your own way:
# helpers.py
from wagtail import hooks
def replace_hook(hook_name, original_fn):
hooks._hooks[hook_name].remove((original_fn, 0))
def inner(fn):
hooks.register('register_page_listing_buttons', fn)
return fn
return inner
Let's say we wanted to remove all buttons from the listing view except the "add child page":
# wagtail_hooks.py
import helpers
#replace_hook('register_page_listing_buttons', page_listing_buttons)
def remove_redundant_buttons(page, page_perms, is_parent=False):
buttons = page_listing_buttons(page, page_perms, is_parent)
if isinstance(page, models.BasePage):
return buttons
else:
# for non-subclasses-of-BasePage allow only adding children
allowed_urls = ['add_subpage']
return [
item for item in buttons
if item.url and resolve(item.url).url_name in allowed_urls
]
Result:

I haven't found such ability in wagtail, but for my case, it was enough to exclude a model from the main menu, so I did next:
#hooks.register('construct_main_menu')
def hide_longlaw_order(request, menu_items):
menu_items[:] = [item for item in menu_items if 'longclaworders' not in item.url]

I know this is an old question, but the short answer is "There is no unregister equivalent".
In standard Django, all the models you see in Django's admin area have been registered in a similar fashion, so unregister makes sense there. In Wagtail, the admin area is completely custom, and 'modeladmin' isn't central to the admin architecture like Django's similar solution is. The various apps within Wagtail do not use import/use it to register their own models. Therefore, there is no way to 'unregister' any of those apps using modeladmin. The 'modeladmin' app is just a utility thing to help you add interfaces for additional models without having to understand all of the various hooks provided by wagtail to do such things.
So, with 'modeladmin' only being used to register custom models, the need for an 'unregister' method is greatly reduced, because in most cases, you'll be in control of what models you are registering via the modeladmin_register method, and so you should be able to just 'not register' those.

Related

How to make a custom method that can be used anywhere in rails app

I wish to make a custom method (e.g. def plus_two(x) x + 2 end and have it be accessible everywhere within the app - that is, accessible in the controller, model, console, views, tests, and any other .rb files. I currently have the same method defined in many areas of the app, and wish to make it DRY
How can this be achieved?
Note: I don't mind if calling the method requires prepending something (I have seen some answers where methods are prepended with :: or with a namespace, but otherwise have a preference to keep code succinct where possible
I have done some reading at similar questions (e.g. this one) but I can't quite get it
Reading the comments it seems like you are just looking for a clear and simple example of a method that is available everywhere in your application:
# in app/models/calculator.rb
module Calculator
def self.plus_two(x)
x + 2
end
end
Which can be called like this:
Calculator.plus_two(8)
#=> 10

Strategy to create multiple representations for the same class based on criteria using ROAR gem?

This is actually a best practices / usage question on hwo to use Roar & representable in Rails, as I didn't find any examples of that. Here are two scenarios. I use decorator pattern.
Scenario 1:
Let's say I have a Product class that has multiple attributes & association. By default when somebody makes a request to api.com/products/1 - I want to show everything I've got, but if somebody makes a request to another action like so api.com/products/1/inventory_details - I only want to show limited view that pertains to inventory ( to make it faster for inventory lookups) or if somebody makes a request to api.com/products/1/assembly_details - I want to return a matrix of related sub assemblies along with some relevant product details.
Questions for Scenario 1 :
Do I create a specific representer for each case like ProductRepresenter, ProductInventoryDetailRepresenter, ProductAssemblyDetailRepresenter or do I use some kind of flow control in the ProductRepresenter?
If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
Can I override this on action level?
Scenario 2:
Let's say I have api.com/products/1 that both my internal application can call but that I also want to expose to my clients. However I don't want my clients to see some of the attributes, like inventory details or maybe just one or two attributes. Also depending on the level access of employee, I want to limit their view / representation.
Questions for Scenario 2 :
Do I create a specific representer for each case like ProductRepresenter, ProductClientViewRepresenter or do I use some kind of flow control in the ProductRepresenter?
If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
Can I override this on an action level - based on the access type like: admin vs inventory_user vs shipping_user?
Any advice would be appriciated. (I'll cross-post this on github in Roar-Rails gem)
Scenario 1 :
Do I create a specific representer for each case like ProductRepresenter, ProductInventoryDetailRepresenter, ProductAssemblyDetailRepresenter or do I use some kind of flow control in the ProductRepresenter?
Yes, please do use separate classes. Don't start with if: and else and that kind of crap as it's done in vanilla Rails. One representer class per context is what I think is right. However, you should use modules and include those into the decorators to share common properties.
If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
You can use ::represents for that, see roar-rails.
Can I override this on action level?
Again, check docs for respond_with and render in roar-rails, they allow setting representers explicitely.
Questions for Scenario 2 :
Do I create a specific representer for each case like ProductRepresenter, ProductClientViewRepresenter or do I use some kind of flow control in the ProductRepresenter?
If it's only about hiding certain properties, you can actually try with :if and inject the context into the rendering/parsing call.
object.to_json(context: "admin")
property :title, if: ->(options) { options[:context] == "admin" }
However, I strongly discourage :if in general as is always ends up in a mess of deciders. Hit me up on github, maybe we can find a way to solve this problem on a general level, with contexts or the like?
and 3., see above.

Navigating through source code efficiently in Ruby

I was trying to find the method being called when Item.where(dst: "video") is called (Item being a Mongoid model). Looking up in the source code, I see that criteria.rb is the place to go to. However, def where calls super. Then Origin::Selectable (included inside Origin::Queryable) defines it:
def where(criterion = nil)
criterion.is_a?(String) ? js_query(criterion) : expr_query(criterion)
end
Now, I would have to see where js_query and expr_query are, see what they do and so on.
It gets tough going through all this source code and modules, finding all the methods and then trying to figure out how it works.
Is there a better way to do this process to find out how things work?
You probably need to improve your editor experience. There are three remarkable abilities (besides many others like Eclipse/Aptana, NetBeans, etc):
RubyMine — not free, but probably the best one;
Atom Editor with RSense plugin — free (plugins are also available for SublimeText and TextMate2;
vim/emacs with [c|e]tags.
Depending on your choice you yield an ability to quickly navigate through your code with either Ctrl+Click or with your preferred keyboard shortcut.
Here on SO this question was asked an amount of times as well: https://stackoverflow.com/search?q=best+ruby+editor
Hope it helps.
If you know the class of the receiver (say A) and the method name (say foo), then you can do:
A.instance_method(:foo).source_location
That will give the file name and the line number in most cases. If it returns nil, then it is likely a C-defined method, which does not rely on other Ruby methods.
Another way is to use the pry gem or the method_source gem.

Internal rails notifications

I'm creating an rails app, which imports some stuff from external service. At the end of that import, user should get an info about how many new items has been imported (it's like a periodical check, which adds just new items to local database. Not all of them each time.). A whole process and method-chain is quite complex so i'm looking for a best-practice on how to pass such information from deeply nested method. Schema looks more or less like that:
some_controller.rb
-> Model.method()
-> Lib1.method1()
-> Lib2.method2()
-> Lib3.method3()
-> Lib4.method4()
-> Lib5.method5()
-> items_import_method()
and i need to somehow pass info about how many new items has been imported from items_imported_method() to some_controller.rb (or any other place this import is fired). The most obvious way of doing that is passing new_items_count var all the way up though this whole method chain but it seems a bit wrong to me. Isn't there any better way?
I was thinking about some kind of internal events/messages system which would let me to subscribe to some custom channel, like activeresource events but maybe there is some well-known and suggested approach for such situation?
Thanks in advance.
One way to tackle this is to create some kind of context container object that has properties any of those steps can manipulate, then pass this in to each method on the way down.
For example:
class ContextExample
attr_accessor :example_field
end
In practice:
#context = ContextExample.new
Lib1.method1(#context)
#context.example_field
# => "Test!"
Where what you're doing is:
module Lib1
def self.method1(context)
Lib2.method2(context)
end
end
module Lib2
def self.method2(context)
context.example_field = "Test!"
end
end
These modules or classes can save context if required, and pass it on when necessary.
If you have well-defined properties you need to set and manipulate, a class with attr_accessor for those usually works pretty well. If it's a more arbitrary thing and you're not sure what might shake out in the end, either use a Hash or an OpenStruct object to capture whatever might come up.

break down a complex search query in Rails 3

I have a controller which has a lot of options being sent to it via a form and I'm wondering how best to separate them out as they are not all being used simultaneously. Ie sometimes no, tags, sometimes no price specified. For prices I have a default price set so I can work around with it always being there, but the tags either need to be there, or not. etc.
#locations = Location.find(params[:id])
#location = #locations.places.active.where("cache_price BETWEEN ? AND ?",price_low,price_high).tagged_with([params[:tags]).order(params[:sort]).paginate :page => params[:page]
I haven't seen any good examples of this, but I'm sure it must happen often... any suggestions? Also, even will_paginate which gets tacked on last should be optional as the results either go to a list or to a google map, and the map needs no pagination.
the first thing to do when refactoring a complex search action is to use an anonymous scope.
Ie :
fruits = Fruit.scoped
fruits = fruits.where(:colour => 'red') if options[:red_only]
fruits = fruits.where(:size => 'big') if options[:big_only]
fruits = fruits.limit(10) if options[:only_first]
...
If the action controller still remains too big, you may use a class to handle the search. Moreover, by using a class with Rails 3 and ActiveModel you'll also be able to use validations if you want...
Take a look at one of my plugins : http://github.com/novagile/basic_active_model that allows you to easily create classes that may be used in forms.
Also take a look at http://github.com/novagile/scoped-search another plugin more specialized in creating search objects by using the scopes of a model.

Resources