Git Product home page Git Product logo

Comments (12)

paulcsmith avatar paulcsmith commented on May 14, 2024

I'll have to look into this more. Under the hood ExMachina uses changesets, so it might not be hard to also cast all the fields. I'm not totally sure ExMachina should handle this, but I'll think about it.

from ex_machina.

henrik avatar henrik commented on May 14, 2024

Thank you :) I think dates/times in factories might be a bit painful otherwise – though maybe there's a nicer way than what I did.

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

In the meantime you could simplify this by extracting a private function and calling Ecto.DateTime.cast

def factory(:package, _attrs) do
  %Package{
    hex_update_at: date_time("2001-02-03T04:05:06Z")
  }
end

defp date_time(date_time) do
  Ecto.DateTime.cast(date_time)
end

from ex_machina.

henrik avatar henrik commented on May 14, 2024

@paulcsmith Good idea, thank you.

I'll sneak this in here since it's quite related: I'm unable to get this working for passed-in dates.

I tried this:

  def factory(:package, attrs) do
    time = Dict.get(attrs, :hex_updated_at, "2001-02-03T04:05:06Z")
    {:ok, cast_time} = Ecto.DateTime.cast(time)

    %Package{
      name: sequence(:name, &"package#{&1}"),
      description: "A package.",
      hex_updated_at: cast_time,
    }
  end

The default value is cast OK, but if I pass in a custom value, it is not cast. I debugged a bit and it seems the changes changeset that ExMachina.Ecto.save_record/3 gets does indeed not have the cast value. I guess I'm misunderstanding something about how you're meant to customize attributes if you also want to massage them a bit.

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

@henrik Ah yes, that is a good point. The problem is that the cast attribute is overridden because the attrs are merged in after the factory/2 function is called. You can do what I said with a hard-coded binary, but if it's from the attrs it won't work unless you custom the save_record function to cast the changes with Ecto.Changeset.cast.

The more I think about it, the more it seems like this should be part of ExMachina.Ecto. I'll probably add it this week or next. Unless you want to try to tackle it in a PR :) I think it just needs to get the changes and pass them through Ecto.Changeset.cast.

from ex_machina.

henrik avatar henrik commented on May 14, 2024

Oh yeah, I just found that part of the code. This bit, right?

  def build(module, factory_name, attrs \\ %{}) do
    attrs = Enum.into(attrs, %{})
    module.factory(factory_name, attrs) |> Map.merge(attrs)
  end

from ex_machina.

henrik avatar henrik commented on May 14, 2024

I would love to tackle it in a PR, but I'm hard-pressed to find time for the project I'm actually trying to work on, so I don't think I'll have the time to spare until that's done :/ I'll customize save_record for now – good idea.

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

No problem, I totally understand. Yes that's the bit that merges the parameters and overrides your cast one. Good luck with your project :)

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

I started work on this, but it relies on elixir-ecto/ecto#1081 before I can get it working with associations. Once a new version of Ecto is released I can pick this work up again

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

I'm going to check this when Ecto 2.0 comes out to see if it is handled automatically when you call Repo.insert!. That would be the most ideal solution, but if that doesn't work I'll try to come up with something else. I do agree that automatically casting would be a lot nicer. That way you can give it an erlang time from GoodTimes (as an example) and it would cast it correctly without having to do explicit conversion every time

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

Chatted with @josevalim about this on IRC

[11:42:03] <paulcsmith_> josevalim Hmm, any ideas on how to handle this? #54 basically, it would be nice if you could set a datetime with an erlang datetime, but you have to manually cast it somewhere, either in the factory or when setting the attrs
[11:42:19] <paulcsmith_> And if you don't have time, no worries :)
[11:43:40] <paulcsmith_> Maybe I could cast everything and then call apply_changes before passing the record to Repo.insert. That's the first thing that comes to mind that might work. Not sure of the ramifications though
[11:44:31] paulcsmith_: i would say you should pass the proper value in
[11:44:45] paulcsmith_: datetime(....) when you call the factory
[11:44:49] paulcsmith_: won't hurt
[11:45:03] build(:package, inserted_at: datetime("...."))
[11:45:07] can even make it a sigil
[11:45:09] ~d(...)
[11:45:12] <paulcsmith_> Yeah that might be the best option. It's what I'm doing now and it does work :)
[11:45:24] <paulcsmith_> Oh the sigil idea sounds interesting. I'll have to try that out.
[11:45:27] <paulcsmith_> Thanks for the input :)

To sum up, the best option might be to add the datetime function as mentioned here to your factory, or add a sigil that does that for you. You'd probably want to make it a public function though so it could be used in your tests to override attributes: build(:package, inserted_at: datetime(GoodTimes.a_day_ago))

I'm considering adding a sigil to ExMachina.Ecto that you could optionally import, but it might be simple enough to just do on your own and we could add it to the README instead.

Does this help @henrik?

from ex_machina.

paulcsmith avatar paulcsmith commented on May 14, 2024

I'm going to close this in favor of #94. Let me know if you have any further feedback on the other issue please :)

from ex_machina.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.