{"action":"created","issue":{"url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/78","labels_url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/78/labels{/name}","comments_url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/78/comments","events_url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/78/events","html_url":"https://github.com/thoughtbot/ex_machina/pull/78","id":123574177,"number":78,"title":"Allow to use custom changeset","user":{"login":"tuvistavie","id":1436271,"avatar_url":"https://avatars.githubusercontent.com/u/1436271?v=3","gravatar_id":"","url":"https://api.github.com/users/tuvistavie","html_url":"https://github.com/tuvistavie","followers_url":"https://api.github.com/users/tuvistavie/followers","following_url":"https://api.github.com/users/tuvistavie/following{/other_user}","gists_url":"https://api.github.com/users/tuvistavie/gists{/gist_id}","starred_url":"https://api.github.com/users/tuvistavie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tuvistavie/subscriptions","organizations_url":"https://api.github.com/users/tuvistavie/orgs","repos_url":"https://api.github.com/users/tuvistavie/repos","events_url":"https://api.github.com/users/tuvistavie/events{/privacy}","received_events_url":"https://api.github.com/users/tuvistavie/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-12-22T23:12:24Z","updated_at":"2015-12-23T05:25:44Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/thoughtbot/ex_machina/pulls/78","html_url":"https://github.com/thoughtbot/ex_machina/pull/78","diff_url":"https://github.com/thoughtbot/ex_machina/pull/78.diff","patch_url":"https://github.com/thoughtbot/ex_machina/pull/78.patch"},"body":"Hi,\r\nI think that changeset is quite an important part of ecto model creation,\r\nbut I could not find a way to use them with factories, so I changed the `save_record`\r\nfunction to be able to use a custom changeset function.\r\nWith this change, the user can provide a `make_changeset/2` function in the factory to create\r\nthe changeset using the one defined in the model, or anywhere else.\r\nAs for `factory/1`, pattern matching can be used to choose the `make_changeset` function.\r\nIf nothing matches (e.g. `make_changeset/2` is not defined), we fallback to `Ecto.Changeset.change`.\r\n\r\nHere is an example\r\n\r\n```elixir\r\n  defmodule Factory do\r\n    use ExMachina.Ecto, repo: TestRepo\r\n\r\n    def factory(:user) do\r\n      %User{\r\n        name: \"John Doe\",\r\n        admin: false\r\n      }\r\n    end\r\n\r\n    def factory(:article) do\r\n      %Article{\r\n        title: \"My Awesome Article\",\r\n        author: build(:user)\r\n      }\r\n    end\r\n\r\n    def make_changeset(%User{} = user, changes) do\r\n      User.changeset(user, changes)\r\n    end\r\n  end\r\n\r\n```"},"comment":{"url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/comments/166806866","html_url":"https://github.com/thoughtbot/ex_machina/pull/78#issuecomment-166806866","issue_url":"https://api.github.com/repos/thoughtbot/ex_machina/issues/78","id":166806866,"user":{"login":"tuvistavie","id":1436271,"avatar_url":"https://avatars.githubusercontent.com/u/1436271?v=3","gravatar_id":"","url":"https://api.github.com/users/tuvistavie","html_url":"https://github.com/tuvistavie","followers_url":"https://api.github.com/users/tuvistavie/followers","following_url":"https://api.github.com/users/tuvistavie/following{/other_user}","gists_url":"https://api.github.com/users/tuvistavie/gists{/gist_id}","starred_url":"https://api.github.com/users/tuvistavie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tuvistavie/subscriptions","organizations_url":"https://api.github.com/users/tuvistavie/orgs","repos_url":"https://api.github.com/users/tuvistavie/repos","events_url":"https://api.github.com/users/tuvistavie/events{/privacy}","received_events_url":"https://api.github.com/users/tuvistavie/received_events","type":"User","site_admin":false},"created_at":"2015-12-23T05:25:44Z","updated_at":"2015-12-23T05:25:44Z","body":"@paulcsmith Thanks for the quick reply.\r\nAs the idea of changeset is quite specific to Ecto, I thought that something adapter specific could be more efficient here.\r\n\r\nThe use case is quite simple: I use the changeset to do what would be done in `before_create`, or some ActiveRecord callback in Rails, for example generating attributes.\r\nWhat I added in the tests (generating a token for the user) is a sample usage.\r\n\r\nAs there is no standard way to deal with changesets in ex_machina, I have things like this in my factories\r\n\r\n```elixir\r\n  def factory(:user) do\r\n    user = %User{\r\n      name: sequence(:name, &(\"name-#{&1}\"))\r\n    }\r\n    Map.merge(user, User.changeset(user).changes)\r\n  end\r\n```\r\n\r\nThis should work for most cases I think, but looks quite unintuitive for something which is very common\r\nwhen using Ecto.\r\n\r\nIt gets worse when I need to choose which changeset to use, as I cannot have it in my factory anymore.\r\nFor example, in my project, I have two different changesets for my `User` model: `admin_changeset` and `changeset`.\r\nWith the current implementation, I have to do something like `build(:user) |> with_admin_changeset |> create`.\r\nWith the proposition above, I could write `create(:user, changeset: :admin)` and pattern match in `make_changeset`, which would be a lot cleaner.\r\n\r\nAbout #35, I would still have to transform `map -> changeset -> map` which will get transformed to a `changeset` a moment later, but the multiple changeset case would be easier to use.\r\nHowever, I do not like the idea of calling an internal function. If it were to be implemented,\r\nI would rather see something with a signature like `build(map, map) :: map`."}}