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

🧹🔨🥗Marketplace: Show Order#delivery_window in Order::EmailReceiptComponent #1319

Merged

Conversation

zspencer
Copy link
Member

@zspencer zspencer commented Apr 6, 2023

So, the delivery_window field which can either be a plain string or a particular date or even a date range is a much more sophisticated object.

I took some time to explore what it could look like to use ActiveModel::Types to create a value object which can take responsibility for representing the data more appropriately.

I think the next step would be to back the Delivery class with a marketplace_deliveries table and move Order#contact_email, etc. into it.

In the meantime, I also added some tests to where the delivery_window is being used, so that when / if we make that change we have some guard rails in place.

No UI changes, but this does add capybara and configure our view_component library for testing.

@zspencer zspencer force-pushed the marketplace/delivery-schedule-is-shown-on-order-confirmation branch from b60fd1c to 38ff75f Compare April 7, 2023 05:34
Copy link
Member Author

@zspencer zspencer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a weird PR. Apologies in advance.

I noticed that the Order#delivery_window was not showing up in the EmailReceiptComponent in production, but it was in the mailer_preview. That was because I was using a FactoryBot.build(:marketplace_order) to populate the values, so the delivery window had never needed to be retrieved from the database! And I had done the same in the Marketplace::OrderPlacedMailer specs... So at no time was Order#delivery_window being called on an Order that had actually been pulled out of the database.

Womp. Womp.

And when I was testing it via the UI, I was using the Cart object... Which did have a Cart#delivery_window.

I started by just copy and pasting the delivery_window method into Order, but that offended my oh-so-delicate sensibilities and I revolted. And since I ... reallllllly want.... a Delivery class..... I thought "Well, what if I sprout that Delivery model?! It sounds like the time!"

And I wanted to relearn the ActiveRecord::Type bits since I haven't had much time to do hands-on-keys coding in a bit; and I want to have a better feel for how the pieces work together...

So anyway, that's all the justification I have for why I didn't create a marketplace_deliveries table and store the data that I've been copy-pasting between tables.

I could see wanting to go down that path sooner rather than later tho. I was really hoping the Type stuff would feel like a solid win...

I'm going to add some more precise tests at the Type and Model level.

@@ -35,7 +35,7 @@
expect { perform_request }
.to change(delivery, :contact_email).to(delivery_attributes[:contact_email])
.and change(delivery, :contact_phone_number).to(delivery_attributes[:contact_phone_number])
.and change(delivery, :delivery_window).to(DateTime.parse(delivery_attributes[:delivery_window]))
.and change { delivery.reload.delivery_window.value }.to(delivery_attributes[:delivery_window])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels clunky as heck

@@ -12,6 +12,7 @@ class Order < Record
has_many :products, through: :ordered_products, inverse_of: :orders

has_encrypted :delivery_address
attribute :delivery_window, ::Marketplace::Delivery::WindowType.new
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this should work with delegate :window, to: :delivery, prefix: true

Copy link
Member Author

@zspencer zspencer Apr 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note! It does not becausebecomes does not re-initialize the data from the database, so the attribute needs to be selected and cast(ed?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will work when we make a marketplace_deliveries table instead of using the becomes hack.

DateTime.parse(super) || 48.hours.from_now
rescue Date::Error => _e
48.hours.from_now
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But hey at least I didn't copy and paste this code everywhere 🤣

<div>
<%= form.label attribute %>
<%= form.datetime_field attribute %>
<%= form.datetime_field attribute, disabled: disabled %>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this could be merged independently, and maybe wombo-comboed with a FieldComponent so more of our :x_field partials have standardized inputs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wombo-comboed! That's a new one for me.

@zspencer zspencer requested review from anaulin and a team April 8, 2023 01:20
@zspencer zspencer changed the title Marketplace: Sprout Delivery::Window object 🧹🔨🥗Marketplace: Sprout Delivery::Window object Apr 8, 2023
@zspencer zspencer marked this pull request as ready for review April 8, 2023 01:21
@zspencer zspencer added ✨ feature Reduces Client's Burden or Grants them Benefits 🛠️ infrastructure ci, build, deploy, networking, etc. 🥗 test automation Adds some automated tests. V nutritious. labels Apr 8, 2023
zspencer added 8 commits April 7, 2023 18:58
- #1185

So, the `delivery_window` field which can either be a plain string or a
particular date or even a date range is a much more sophisticated
object.

I took some time last night to explore what it could look like to use
`ActiveModel::Type`s  to create a value object which can take
responsibility for representing the data more appropriately.

That said, I think `store_model` will be better ™️, but I didn't want
to try to dig into that just yet.
We can't use `alias_method` with `attribute`, which is weird but ok.
OK, that makes sense... We keep the type castin gin the type... and that
makes everything else lighter.
@zspencer zspencer force-pushed the marketplace/delivery-schedule-is-shown-on-order-confirmation branch from d2414a0 to cd0c585 Compare April 8, 2023 01:58
Keeps the refactor just a tiny bit more cleaner and full
@zspencer zspencer changed the title 🧹🔨🥗Marketplace: Sprout Delivery::Window object 🧹🔨🥗Marketplace: Show Order#delivery_window in Order::EmailReceiptComponent Apr 8, 2023
alias_method :==, :eql?

def time_like?
value.respond_to?(:strftime)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe inlining this method would make the strftime method clearer -- you are calling strftime if it responds to it -- saving the extra indirection of going "is time_like? a built-in thing? oh, no, it is defined down here, let's see... oh, i see".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, there's an indirection bump but time_like? is used in a few other places (in particular figuring out which field to render for the form and how to present the window on the receipt)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, fair enough.


def strftime(*args, **kwargs)
return value.strftime(*args, **kwargs) if time_like?
value
Copy link
Member

@anaulin anaulin Apr 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callers of strftime will probably expect a string coming back from this call. Is value a string? Or can it be something else that should be cast to a string? (ETA: Something else that isn't time-like)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oo that's a good point... I could just call to_s? For now, value is either a string or a DateTime; but if we start wanting it to hold a date range or other less primitive data structures it will be weird to return them.

Copy link
Member

@anaulin anaulin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not that weird. But perhaps I'm not the best judge of that.

Thanks for all the extra testing goodness!

@zspencer zspencer merged commit 3d6825d into main Apr 8, 2023
@zspencer zspencer deleted the marketplace/delivery-schedule-is-shown-on-order-confirmation branch April 8, 2023 03:08
@zspencer zspencer added this to the 1.0 - Andromeda milestone May 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ feature Reduces Client's Burden or Grants them Benefits 🛠️ infrastructure ci, build, deploy, networking, etc. 🥗 test automation Adds some automated tests. V nutritious.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants