Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Remove dependency on view_context #288

Closed
n-rodriguez opened this issue May 5, 2018 · 10 comments
Closed

[RFC] Remove dependency on view_context #288

n-rodriguez opened this issue May 5, 2018 · 10 comments
Assignees
Labels

Comments

@n-rodriguez
Copy link
Member

n-rodriguez commented May 5, 2018

Hi there!

In order to have a cleaner API for ajax-datatables-rails and in a long term view for this gem, I'd like to remove the view_context dependency by directly injecting the params hash.

It would have some advantages :

  • start to reduce coupling with Rails (there's still room for improvements but it would be a start)
  • ajax-datatables-rails would be compatible with Rails API which doesn't have view_context (Using in API only mode? #240)
  • it would make tests easier for users (you have only one hash to pass to build and test a datatable, don't need Capybara tests anymore)
  • the view_context is a quite big object to pass around, passing a hash would be lighter
  • it encourages developers to have a clean object design

But it also have some drawbacks :

  • it changes the API :
# before
  respond_to do |format|
    format.json { render json: UserDatatable.new(view_context) }
  end

# after
  respond_to do |format|
    format.json { render json: UserDatatable.new(params) }
  end

If you really want to inject the view_context as before you can still use the options hash :

# Controller
  respond_to do |format|
    format.json { render json: UserDatatable.new(params, view_context: view_context) }
  end

# Datatable
class ApplicationDatatable < AjaxDatatablesRails::Base
  extend Forwardable
  attr_reader :view
  def initialize(params, opts = {})
    @view = opts[:view_context]
    super
  end
end

class MyCustomDatatable < ApplicationDatatable
end

I'm testing this idea on a real world application (45 datatables) with this branch : https://github.com/jbox-web/ajax-datatables-rails/tree/feat/rails-api and so far it works very well :) (I made the migration on Draper before)

Tests are passing : https://travis-ci.org/jbox-web/ajax-datatables-rails/builds/375203557 🎉

The idea was a lot inspired by Trailblazer which I use in my app 👍

What do you think? It would be for a 0.5 release.

@n-rodriguez n-rodriguez self-assigned this May 5, 2018
@n-rodriguez n-rodriguez added the RFC label May 5, 2018
@n-rodriguez
Copy link
Member Author

cc @ajahongir

@Nittarab
Copy link

Oh, this is an important change... I have a question: are you sure that Draper are still updated? Don't see a lot of activity in that repo.
Btw, if I include an Helper where I have one method that use the link_to method, this will not work right?

@antillas21
Copy link
Collaborator

What do you think? It would be for a 0.5 release.

I believe going this way, you should bump to 1.0 release, as this is a major/breaking change.
I like the idea on removing view_context dependency.

as for:

are you sure that Draper are still updated?

You don't need a project to have (code) activity every so often, IMHO, you only need a stable project.

These are (literally) my two cents 🙂

@ajahongir
Copy link
Collaborator

ajax-datatables-rails would be compatible with Rails API which doesn't have view_context (#240)

It sounds good and totally agree with @antillas21 to bump up 1.0 release

@n-rodriguez
Copy link
Member Author

n-rodriguez commented May 17, 2018

Hi!

Oh, this is an important change... I have a question: are you sure that Draper are still updated? Don't see a lot of activity in that repo.

Actually Draper is an optional dependency and will not be installed by ajax-datatable-rails.
Draper is just a convenient way of formatting data before rendering them in JSON.
You can also use the way I proposed above.
I also agree with @antillas21 :

You don't need a project to have (code) activity every so often, IMHO, you only need a stable project.

Also

I believe going this way, you should bump to 1.0 release, as this is a major/breaking change.

I agree that at some point we should bump to 1.0 but I'd love to fix #228 and some other issues before releasing a 1.0. The goal is to have a stable API for the 1.0 release. I don't know yet how solving #228 would impact the API. Thus the 0.5 release.
As far as I remember this change doesn't break semver since we're still in 0.x.x.
What do you think?

@n-rodriguez
Copy link
Member Author

And thanks everybody for your answers :)

@n-rodriguez
Copy link
Member Author

n-rodriguez commented Jun 4, 2018

Hi there! After a lof of thinking on how solve this #228 I came with some solutions.
First of all we should not extend AjaxDatatablesRails::Base class at runtime as it breaks Ruby method cache : https://github.com/jbox-web/ajax-datatables-rails/blob/master/lib/ajax-datatables-rails/base.rb#L120. Not very good for performances.

The ORM module should be included in the AjaxDatatablesRails::Base class or subclass.

To solve the "extend at runtime" issue we can :

  • let the user include the AjaxDatatablesRails::ORM::ActiveRecord module in every single class (not very friendly)
  • add a new class AjaxDatatablesRails::ActiveRecord that would inherit from AjaxDatatablesRails::Base and users would inherit from AjaxDatatablesRails::ActiveRecord (a bit more friendly and it let room for AjaxDatatablesRails::Mongoid)

It also removes the need to configure the ORM (a bit of convention over configuration).

Notes: I've already thought of dependency injection but it's not doable due to the current implementation : https://github.com/jbox-web/ajax-datatables-rails/blob/master/lib/ajax-datatables-rails/orm/active_record.rb#L27.
The ORM module knows about the datatable object and you can't inject it as it creates a chicken and egg issue :

def initialize(params, opts = {})
...
@orm = opts.fetch(:orm, ActiveRecord.new(self))
end

but how do you do :

orm = Mongo.new(dt)
dt = PostDatatable.new(params, orm: orm)

Or we can just inject the class name and call .new on it... but it's not very performance oriented. Instantiating a new ORM object that could be included in a class...

On the other side it would make cleaner "interfaces" and responsabilities between objects...

I tried both :

@n-rodriguez
Copy link
Member Author

Finally the "injection" solution doesn't solve the very first issue : "Allow again overriding filter_records, sort_records" so it's a no go :)

@n-rodriguez
Copy link
Member Author

Hi there! Any thoughts on the last proposal? (AjaxDatatablesRails::ActiveRecord vs AjaxDatatablesRails::Base).
With the view_context change it's 2 good reasons to bump to v1.0.0 👍

@n-rodriguez
Copy link
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants