phoenixframework / phoenix_ecto Goto Github PK
View Code? Open in Web Editor NEWPhoenix and Ecto integration with support for concurrent acceptance testing
License: MIT License
Phoenix and Ecto integration with support for concurrent acceptance testing
License: MIT License
I just noticed that phoenix_ecto
build is broken when integrated with the latest ecto
master. Do you think this a problem likely to occur frequently (and thus worth adding some alerts), or it doesn't matter much?
I have heard about other OSS projects that are catching integration issues early on by using e.g. CI build matrices and pointing upstream deps to master branches. I took a stab at it and it was relatively easy to do, albeit mix.exs got more complicated. See: https://travis-ci.org/wojtekmach/phoenix_ecto/builds/116899223, wojtekmach@ffb2852
Please let me know if you'd be interested in this change, and I'm happy to open up a PR. Thanks!
When inserting a changeset/struct if you've set a prefix on insertion the resulting struct does not include the prefix in the Ecto.Schema.Metadata. My expectation is that this value should be set to whatever the value of the prefix was.
Here is the full problem that I'm having:
When testing I will often create some factories that need to be persisted to the database. However I run into issues due to the prefix not being available after insert when I want to find data that would be related to this object.
I'm working on an app that uses UUID's for primary keys. If someone attempts to visit (for example) the show
page for a given resource but the id
is not a valid UUID, an Ecto.CastError
is raised, which results in a 400
status code.
In this case, it might be desirable to change this into a 404
as the resource doesn't exist for the given id
.
Since the default implementation is defined within a dependency, you can't redefine it without a compilation warning: warning: redefining module Plug.Exception.Ecto.CastError
Should we make these default implementations part of the user's application code? Is this warning anything to be concerned about?
I've tried phoenixframework today, which comes with phoenix_ecto. I've setup the credentials and created a migration and a model:
$ cat priv/repo/migrations/20150412101442_create_accounts.exs
defmodule ElixirAccounts.Repo.Migrations.CreateAccount do
use Ecto.Migration
def change do
create table (:accounts) do
add :umt_login_id, :integer
add :firstname, :string
add :lastname, :string
add :birthday, :date
add :uid, :string
add :uid_number, :integer
add :gid_number, :integer
add :mail, :string
add :password, :string
add :umt_user_id, :string
add :account_type, :string
add :account_state, :string
timestamps
end
end
end
$ cat web/models/account.ex
defmodule ElixirAccounts.Account do
use Ecto.Model
schema "accounts" do
field :uid, :string
field :firstname, :string
field :lastname, :string
field :birthday, :date
field :mail, :string
field :password, :string
field :uid_number, :integer
field :gid_number, :integer
field :account_type, :string
field :account_state, :string
field :umt_login_id, :integer
field :umt_user_id, :string
end
end
But I was not able to insert any data to the database by using the model:
$ iex -S mix
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.1.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> alias ElixirAccounts.Repo
nil
iex(2)> alias ElixirAccounts.Account
nil
iex(3)> account = %Account{firstname: "foo", lastname: "bar"}
%ElixirAccounts.Account{meta: %Ecto.Schema.Metadata{source: "accounts", state: :built}, account_state: nil, account_type: nil, birthday: nil,
firstname: "foo", gid_number: nil, id: nil, lastname: "bar", mail: nil,
password: nil, uid: nil, uid_number: nil, umt_login_id: nil, umt_user_id: nil}
iex(4)> Repo.insert(account)
[debug] INSERT INTO "accounts" ("account_state", "account_type", "birthday", "firstname", "gid_number", "lastname", "mail", "password", "uid", "uid_number", "umt_login_id", "umt_user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" nil, nil, nil, "foo", nil, "bar", nil, nil, nil, nil, nil, nil
** (Postgrex.Error) ERROR (not_null_violation): null value in column "inserted_at" violates not-null constraint
(ecto) lib/ecto/adapters/sql/worker.ex:26: Ecto.Adapters.SQL.Worker.query!/4
(ecto) lib/ecto/adapters/sql.ex:187: Ecto.Adapters.SQL.use_worker/3
(elixir_accounts) lib/elixir_accounts/repo.ex:2: ElixirAccounts.Repo.log/2
(ecto) lib/ecto/adapters/sql.ex:394: Ecto.Adapters.SQL.model/5
(ecto) lib/ecto/repo/model.ex:32: anonymous fn/8 in Ecto.Repo.Model.insert/4
Does I've oversee something?
I'd like to use Ecto.Changeset.apply_action/2
in my Phoenix app. I see it's available in version 2.2.1 of Ecto. Are there plans to bump the Ecto version used by phoenix_ecto
to 2.2.1 anytime soon?
I'm not sure if this is the right place to file this issue (or if its even an issue), but I'm fairly perplexed.
I am trying to write some simple model tests that reflect the validations on my user model. The issue is that the validations are running correctly in test, with the exception of the unique_constraing(:email, message: "email taken")
. I would assume that this is a bug in my code, except that it does enforce the email uniqueness from iex. Maybe this has something to do with running the tests async?
my dependencies:
defp deps do
[
{:comeonin, "~> 2.4"},
{:cowboy, "~> 1.0"},
{:gettext, "~> 0.9"},
{:guardian, "~> 0.10.0"},
{:phoenix, "~> 1.1.4"},
{:phoenix_ecto, "~> 3.0.0-rc"},
{:phoenix_html, "~> 2.4"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:poison, "~> 2.0", override: true},
{:postgrex, ">= 0.0.0"}
]
end
my migration:
def change do
create table(:users) do
add :email, :string
add :encrypted_password, :string
timestamps
end
create unique_index(:users, [:email])
end
my validations on the user model:
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> validate_length(:password, min: 8)
|> validate_confirmation(:password, message: "Passwords do not match")
|> unique_constraint(:email, message: "Email already taken")
|> generate_encrypted_password
end
the test that is failing with ** (MatchError) no match of right hand side value:
...
test "if an email is already taken, we get an email error" do
User.changeset(%User{}, @valid_attrs) |> Repo.insert
{:error, changeset} = User.changeset(%User{}, @valid_attrs) |> Repo.insert
end
and the correct behavior which is being tested manually through iex
iex(3)> User.changeset(%User{}, %{email: "[email protected]", password: "password", password_confirmation: "password"}) |> Repo.insert
[debug] QUERY ERROR db=6.4ms
INSERT INTO "users" ("inserted_at","updated_at","email","encrypted_password") VALUES ($1,$2,$3,$4) RETURNING "id" [{{2016, 4, 30}, {23, 54, 37, 0}}, {{2016, 4, 30}, {23, 54, 37, 0}}, "[email protected]", "$2b$12$tpa55J54hwRlnsDM31RyJOkfWKxJptcDMN.cTpvK892y9ZuWKOmkC"]
{:error,
#Ecto.Changeset<action: :insert,
changes: %{email: "[email protected]",
encrypted_password: "$2b$12$tpa55J54hwRlnsDM31RyJOkfWKxJptcDMN.cTpvK892y9ZuWKOmkC",
password: "password"}, errors: [email: {"Email already taken", []}],
data: #MoneyMoneyMoney.User<>, valid?: false>}
Aside: thanks for all the hard work, I'm really loving all things elixir/phoenix!
It appears that the migration process generates an empty migration file instead of a fully formed executable migration file. Thus, here are my findings using phoenix_ecto 2.0
and phoenix 1.1.0
as I work through the Programming Phoenix
ebook.
user.ex:
defmodule Rumbl.User do
use Rumbl.Web, :model
schema "users" do
field :name, :string
field :username, :string
field :password, :string, virtual: true
field :password_hash, :string
timestamps
end
end
$ mix ecto.gen.migration create_user
priv/repo/migrations/20160103224338_create_user.exs:
expected
defmodule Rumbl.Repo.Migrations.CreateUser do
use Ecto.Migration
def change do
create table(:users) do
add :name, :string
add :username, :string, null: false
add :password_hash, :string
timestamps
end
create unique_index(:users, [:username])
end
end
actual
defmodule Rumbl.Repo.Migrations.CreateUser do
use Ecto.Migration
def change do
end
end
Lastly, there might be a bit of duplication with field field_name
statements within the model and the add field_name
statements within the migration but I prefer to just see this information within the model.
When I create a form with a Ecto.Changeset
with changes, I would expect that the changes are taken into account when the form is populated. Right now only the params are taken into account.
changeset = %Model{number: 1}
|> Ecto.Changeset.cast(%{number: 2}, [:number])
|> Ecto.Changeset.put_change(:number, 3)
Phoenix.HTML.FormData.to_form(changeset)
|> Phoenix.HTML.Form.field_value(:number) # => 2, I would expect this to be 3
Similar to elixir-ecto/ecto#875.
Hi,
I am NOT sure if this is even an issue or this is is by design, so please forgiving my ignorance. Elixir/Phoenix newbie here.
I understand that Repo.update! will raise StaleModelError if DB conflicts are encountered, but from my understanding, Repo.update should return an error tuple (e.g. {:error, changeset}). What I am seeing is that Repo.update is also raising the error, so I have to do try....rescue for now.
I am using phoenix_ecto 2.0, which I think it is Ecto 1.1.5 under the hood. I believe Ecto 2.0 beta is showing the same behavior, which leads me to think this is how it is designed to begin with. Again, if this is the case, please pardon me for filing this as an issue.
Many Thanks,
Allen
It would seem to make sense to do something like this:
defimpl Plug.Exception, for: Ecto.InvalidChangesetError do
def status(_), do: 422 # Unprocessable Entity
end
Thoughts? I'm happy to make a PR if this is a desired direction.
Hi,
for example:
defmodule HelloPhoenix.Repo.Migrations.UpdateTimestampFields do
use Ecto.Migration
def up do
"ALTER TALBE posts ALTER COLUMN created_at TYPE date"
end
Running this produces:
mix ecto.migrate Repo
12:44:32.151 [info] == Running HelloPhoenix.Repo.Migrations.UpdateTimestampFields.up/0 forward
12:44:32.155 [info] == Migrated in 0.0s
Expected to see something like:
ERROR: syntax error at or near "TALBE"
I ran into the problem that mix ecto.migrate
and mix ecto.migrations
does not see my last migration files in production mode. But sees them in mode dev
mars@ubuntu:~/temp_phoenix/my_balance$ mix ecto.migrations
Repo: MyBalance.Repo
Status Migration ID Migration Name
--------------------------------------------------
up 20170315204850 create_user
up 20170319184713 create_session
up 20170321195200 create_budget
up 20170321200354 create_users_budgets
up 20170322193636 add_name_to_budgets
up 20170323200738 create_operation
up 20170414202921 create_category
up 20170414203307 add_category_id_to_operations
up 20170416184614 add_confirm_token_to_users
up 20170420204700 add_user_timestamp_to_operations
up 20170421195002 create_invitation_code
up 20170421214515 add_constraint_to_user_budget
mars@ubuntu:~/temp_phoenix/my_balance$ MIX_ENV=prod mix ecto.migrations
Repo: MyBalance.Repo
Status Migration ID Migration Name
--------------------------------------------------
up 20170315204850 create_user
up 20170319184713 create_session
up 20170321195200 create_budget
up 20170321200354 create_users_budgets
up 20170322193636 add_name_to_budgets
up 20170323200738 create_operation
up 20170414202921 create_category
up 20170414203307 add_category_id_to_operations
I tried to execute MIX_ENV=prod mix ecto.drop
and MIX_ENV=prod mix ecto.create && MIX_ENV=prod mix ecto.migrate
, but this did not work.
What could be the reason?
versions: phoenix_ecto 3.2.3 , ecto 2.1.4
After running
mixโโ โโphoenix.gen.htmlโโ โโVideoโโ โโvideosโโ โโuser_id:references:usersโโ โโโurl:stringโโ โโtitle:stringโโ โโdescription:textโ
and applying all indicated additional modifications I get a Compilation Error below:
== Compilation error on file web/controllers/video_controller.ex ==
** (CompileError) web/controllers/video_controller.ex:24: undefined function video_path/2
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1```
When displaying a template that iterates over a table containing some times, the following error occurred:
protocol Phoenix.HTML.Safe not implemented for %Ecto.Time{hour: 0, min: 0, sec: 0}
We use phoenix_ecto, but does not always want to return or handle Ecto.NoResultsError
as 404 pages. Would it be possible to make the implementations configurable (so that one might opt out of them while still using the rest of the project)?
Let's assume we have the following route:
item_path GET /item/:id Project.Web.ItemController :show
In the Controller, we'd use Repo.get!(Item, id)
which of course should result in a 404 if not found since there is no matching resource.
But if we might also want to fetch other data through Ecto bang functions, where a NoResultsError is not an indication that the resource is unavailable but rather an application or data integrity error. In those cases we'd like to handle the error differently, and not return the 404 page.
In our case we would probably make the result explicit, such as using a Repo.get_or_404!
helper, that would raise something like Project.NotFoundError
with a custom implementation for Plug.Exception
.
Since Ecto callbacks are deprecated now, how do we handle after/before actions now? Before actions can be done using changesets, but what about after callbacks.
I need to broadcast an event after data is inserted. Any even simple example how to do it now?
I'm expecting my form to be populated via changeset (this is with ecto-2.0.0-rc6) and phoenix_ecto 3.0
I needed to explicitly do this ๐
changeset = Map.put(changeset,:params, params["user"])
Am I right in expecting this Form to have the changeset fields populated by default?
https://hexdocs.pm/phoenix_ecto is returning a 404
Unexpected per https://hex.pm/docs/tasks#hex_publish
I discovered this when I found the docs weren't available to Dash.
A relatively straightforward migration failed while rolling back. Appears to be while attempting to drop the "company_id" column.
def change do
alter table(:connections) do
add :company_id, references(:companies)
remove :pos_id
end
create index(:connections, [:company_id])
end
Error message:
17:10:28.022 [info] drop index connections_company_id_index
17:10:28.023 [info] alter table connections
** (FunctionClauseError) no function clause matching in Ecto.Adapters.Postgres.Connection.intersperse_map/4
(ecto) lib/ecto/adapters/postgres/connection.ex:901: Ecto.Adapters.Postgres.Connection.intersperse_map(nil, ", ", #Function<1.80844679/1 in Ecto.Adapters.Postgres.Connection.column_changes/2>, [[], ["DROP COLUMN ", [34, "company_id", 34]], ", "])
Versions:
Ecto: 2.1.3, Phoenix_Ecto: 3.0.1
For some reason, I have to add option: @derive {Phoenix.Param, key: :_id}
to my model.
This error happened after that
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Mongo.Ecto.update/7
(mongodb_ecto) lib/mongo_ecto.ex:483: Mongo.Ecto.update(Snappy.Repo, %{context: nil, model: Snappy.Tracking, source: {nil, "trackings"}, state: :loaded}, [current_status: "picked_up", external_carrier: "VTP", external_tracking: "SNPE37043100000186", updated_at: {{2015, 12, 8}, {21, 3, 49, 0}}], [_id: "E37043100000186"], nil, [], [])
(ecto) lib/ecto/repo/model.ex:253: Ecto.Repo.Model.apply/4
(ecto) lib/ecto/repo/model.ex:152: anonymous fn/10 in Ecto.Repo.Model.do_update/4
(ecto) lib/ecto/repo/model.ex:25: Ecto.Repo.Model.update!/4
Hello,
I have an Ecto schema with a Money.Ecto.Type
field and noticed the following:
When rendering a changeset from the schema without errors, field_value
returns a Money
struct.
In the presence of an error (on another field), it returns the value represented as a string like "0.80".
This broke a custom field render function of mine.
Note that the behaviour has been changed by upgrading ecto (!) from ref "52b354" to 2.1.4. Previously, field_value
would always return Money
structs.
The new behaviour is possibly desired, if so I would like to understand why.
@jeregrine @drewolson @paulcsmith, to release I am waiting on your feedback here:
https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/json.ex
And the tests:
https://github.com/phoenixframework/phoenix_ecto/blob/master/test/phoenix_ecto/json_test.exs
Date, Time, DateTime and Decimal are all represented as strings. We also implemented JSON rendering for changesets and all we do is to render the errors as a JSON object.
If you are OK with those, I am releasing v0.2.0 and updating Phoenix master to depend on it.
Thank you! <3
I brought this idea to @ericmj and @chrismccord today, but it seems that we might need some more opinions on the matter.
The first idea was to add mix ecto.seed
to Ecto. It would read seed.exs
from priv/repo/seeds
. This would allow users to seed their database following a nice convention.
Eric pointed out that this can be done really easily with mix run priv/repo/seeds.exs
. But now I realize that the application probably needs to be started (or at least the Repo
connected first). So it might be nice to provide a way to do this without boilerplate.
Eric also mentioned that maybe this should not be something concerned with Ecto but a separate application. I thought about phoenix_ecto
for this.
Talking with Chris, he mentioned that we could just handle this by generating a mix task for the application my_app/lib/mix/tasks/seed.ex
and have empty seed/1
functions base on the environment that the user would have to fill out.
I still think that it would be nice to separate the task itself from the seed files. The task would start the repo and use priv/repo/seeds/seed.exs
to insert records and whatnot. I think it's important to provide a clean interface for this.
# priv/repo/seeds/seed.exs
use PhoenixEcto.Seed
import_seeds "users_#{Mix.env}.exs"
import_seeds "posts_#{Mix.env}.exs"
import_seeds "categories_#{Mix.env}.exs"
# priv/repo/seeds/users_dev.exs
use PhoenixEcto.Seed
%User{name: "Sonny Scroggin", admin: true} |> Repo.insert
...
mix my_app.seed
Thoughts?
Noticing a problem with this line:
https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L202
The following is returned in an embedded relation now:
{:ok,
{:embed,
%Ecto.Embedded{cardinality: :one, field: :config, on_replace: :raise,
owner: SlackCoder.Models.User, related: SlackCoder.Models.User.Config}}}
Wasn't quite sure what to do since the cast
field is no longer available...
Heres the stacktrace produced when attempting to do a inputs_for
call on an embedded relation:
[error] #PID<0.3365.0> running SlackCoder.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /users/1/edit
** (exit) an exception was raised:
** (ArgumentError) could not generate inputs for :config from SlackCoder.Models.User. Check the field exists and it is one of embeds_* or has_*
(phoenix_ecto) lib/phoenix_ecto/html.ex:206: Phoenix.HTML.FormData.Ecto.Changeset.find_inputs_for_type!/2
(phoenix_ecto) lib/phoenix_ecto/html.ex:35: Phoenix.HTML.FormData.Ecto.Changeset.to_form/4
(phoenix_html) lib/phoenix_html/form.ex:267: Phoenix.HTML.Form.inputs_for/4
(slack_coder) web/templates/user/form.html.eex:24: anonymous fn/2 in SlackCoder.UserView.form.html/1
(phoenix_html) lib/phoenix_html/form.ex:235: Phoenix.HTML.Form.form_for/4
(slack_coder) web/templates/user/form.html.eex:1: SlackCoder.UserView."form.html"/1
(slack_coder) web/templates/user/user.html.eex:8: SlackCoder.UserView."user.html"/1
(slack_coder) web/templates/layout/app.html.eex:50: SlackCoder.LayoutView."app.html"/1
(phoenix) lib/phoenix/view.ex:344: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:633: Phoenix.Controller.do_render/4
(slack_coder) web/controllers/user_controller.ex:1: SlackCoder.UserController.action/2
(slack_coder) web/controllers/user_controller.ex:1: SlackCoder.UserController.phoenix_controller_pipeline/2
(slack_coder) lib/phoenix/router.ex:261: SlackCoder.Router.dispatch/2
(slack_coder) web/router.ex:1: SlackCoder.Router.do_call/2
(slack_coder) lib/slack_coder/endpoint.ex:1: SlackCoder.Endpoint.phoenix_pipeline/1
(slack_coder) lib/plug/debugger.ex:92: SlackCoder.Endpoint."call (overridable 3)"/2
(slack_coder) lib/phoenix/endpoint/render_errors.ex:34: SlackCoder.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
Crashing line is here: https://github.com/mgwidmann/slack_coder/blob/update_deps/web/templates/user/form.html.eex#L24-L25
Since there is not a new RC release of phoenix_ecto and the latest Ecto RC handles the Poison encoding, there is code duplication which causes my exrm
builds to fail.
Or at least, I think that's what's happening, since it works with phoenix_ecto
master. :)
==> phoenix_ecto Compiling 5 files (.ex) warning: redefining module Poison.Encoder.Ecto.Association.NotLoaded (current version loaded from /Users/trond/dev/elixir/sites/neva/_build/dev/lib/ecto/ebin/Elixir.Poison.Encoder.Ecto.Association.NotLoaded.beam)
===> Provider (release) failed with: {error,
{rlx_prv_assembler,
{release_script_generation_error,
systools_make,
{duplicate_modules,
[{{'Elixir.Poison.Encoder.Ecto.Association.NotLoaded',
ecto,
"/app/rel/neva/lib/ecto-2.0.0-rc.6/ebin"},
{'Elixir.Poison.Encoder.Ecto.Association.NotLoaded',
phoenix_ecto,
"/app/rel/neva/lib/phoenix_ecto-3.0.0-rc.0/ebin"}}]}}}}
==> ERROR: "Failed to build release. Please fix any errors and try again."
This seems to work:
add :gender, :enum, null: false, size: "'male', 'female'"
Is this the proper way to do it? It just seems weird to use the size
option for this. Although I suppose the generated DDL is technically valid.
Hi,
There is some overlap between ecto and phoenix_ecto for the Poison encoders.
phoenix_ecto builds these beam files:
Elixir.Poison.Encoder.Decimal.beam
Elixir.Poison.Encoder.Ecto.Changeset.beam
Elixir.Poison.Encoder.Ecto.Date.beam
Elixir.Poison.Encoder.Ecto.DateTime.beam
Elixir.Poison.Encoder.Ecto.Time.beam
ecto has these:
Elixir.Poison.Encoder.Decimal.beam
Elixir.Poison.Encoder.Ecto.Date.beam
Elixir.Poison.Encoder.Ecto.DateTime.beam
Elixir.Poison.Encoder.Ecto.Time.beam
Looking at the source they are mostly the same, but phoenix_ecto has encoding for Changeset too. Right now we have duplicate beam files in the code path; could they all be merged into ecto including Changeset, and removed from phoenix_ecto?
I was scratching my head wondering why my :errors
was empty in the form object even though there are errors in the changeset.
Then I found this commit d374ed8 which sets errors to empty if the action is nil
.
My question is, why do this? Are we supposed to usually set an action on the changeset? I can't find any docs on this or even how/why we should do that.
Hi Guys,
first thanks for the amazing work on this.
I have recently updated to phoenix_ecto 3.3.0
and have noticed a bit of code stopped working.
With 3.2.3 I could do something like:
ids = List.flatten([[1, 2, 3],[4, 5]])
from b in table,
where: b.id in ^ids,
limit: ^limit,
offset: ^offet
If I try the same with 3.3.0 it generates:
#Ecto.Query<from u in User, where: u.id in ^[1, 2, 3, 4, 5], limit: ^10, offset: ^20>
...WHERE (s0."user_id" = ANY($1)) LIMIT $7 OFFSET $8 [[1, 2, 3, 4, 5], 10, 20]
and obviously doesn't work.
Is my usage incorrect or something broke with the latest update?
thanks!
Hi,
I am currently working on Hound and would like to have your feedback to make concurrent acceptance tests smoother.
After having discussed with @josevalim in HashNuke/hound#71, here is what we came up with:
HashNuke/hound#98
Basically, we can now pass any metadata to the driver, it will be sent through the UA string.
The serialization/deserialization will be handled automatically so that it works with any browser or driver.
An improvement compared to the current approach is that we do not rely on cookies, so PhantomJS should also work fine, at least for the Ecto part.
A sample usage would be
setup do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(YourApp.Repo)
Hound.start_session(metadata: %{repo: YourApp.Repo, owner: self()}
end
We could then have the plug to extract the metadata and allow the connection:
defmodule Phoenix.Ecto.SQL.Sandbox do
def init(opts \\ []) do
Keyword.get(opts, :sandbox, Ecto.Adapters.SQL.Sandbox)
end
def call(conn, sandbox) do
conn
|> get_resp_header("user-agent")
|> List.first
|> Hound.Metadata.extract
|> allow_sandbox_access(sandbox)
conn
end
defp allow_sandbox_access(%{repo: repo, owner: owner}, sandbox) do
Enum.each(List.wrap(repo), &sandbox.allow(&1, owner, self()))
end
defp allow_sandbox_access(_metadata, _sandbox), do: :ok
end
I believe the above example should work but I did not try it yet.
As it depends directly on Hound, I am not sure if it is ok to add
this here, or if it is better we create another package dependent
on both phoenix_ecto
and hound
to avoid adding dependencies.
Anyway, I would very much like to have your feedback.
Thank you!
When I try to install phoenix_ecto via mix I have an error, I don't have this problem if I clone the repository with git in a shell.
{:phoenix, github: "phoenixframework/phoenix"},
{:phoenix_ecto, github: "phoenixframework/phoenix_ecto"},
* Getting phoenix_ecto (git://github.com/phoenixframework/phoenix_ecto.git)
Cloning into '/Users/stephane/dev/oci/deps/phoenix_ecto'...
remote: Counting objects: 123, done.
remote: Total 123 (delta 0), reused 0 (delta 0), pack-reused 123
Receiving objects: 100% (123/123), 15.43 KiB | 0 bytes/s, done.
Resolving deltas: 100% (46/46), done.
Checking connectivity... done.
fatal: reference is not a tree: ea5f6d90cfae8ab037d0cbe765660c98167ed4fd
** (Mix) Command `git --git-dir=.git checkout --quiet ea5f6d90cfae8ab037d0cbe765660c98167ed4fd` failed
Do you have an idea?
Thanks
I use wallaby
for my feature tests, and my application uses websockets internally. While simple http request works pretty well, socket implementation brings me
Request: GET /socket/websocket?token=xxxx&vsn=1.0.0
** (exit) an exception was raised:
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.577.0>.
When using ownership, you must manage connections in one
of the three ways:
* By explicitly checking out a connection
* By explicitly allowing a spawned process
* By running the pool in shared mode
The first two options require every new process to explicitly
check a connection out or be allowed by calling checkout or
allow respectively.
The third option requires a {:shared, pid} mode to be set.
If using shared mode in tests, make sure your tests are not
async.
If you are reading this error, it means you have not done one
of the steps above or that the owner process has crashed.
See Ecto.Adapters.SQL.Sandbox docs for more information.
I have an Repo.get
query inside my UserSocket
in order to authenticate
When a changeset is used to create a %Phoenix.HTML.Form[}
errors seems to be ignored.
I found the explanation but I can't firgure why this line is used
https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L232
If I send a changeset containing errors to Phoenix.HTML.Form.form_for I would expect errors to be transmitted.
# Changeset with an error
comment = Comment.changeset(%Comment{username: "Hello"}, %{username: ""})
form_for comment, my_path, fn f ->
IO.inspect(f)
end
# IO.inspect(f)
%Phoenix.HTML.Form{
data: %Blogmvc.Comment{ .... },
errors: [], # <= not expected
hidden: [],
....
source: #Ecto.Changeset<
action: nil,
changes: %{username: nil},
errors: [username: {"can't be blank", []}],
data: #Blogmvc.Comment<>,
valid?: false
>
}
Maybe I'm missing something but action should not matter for this right ?
I tried to make mix ecto.migrate in my Phoenix application and surprisingly found the following error:
warning: could not find repositories for application :adah.
You can avoid this warning by passing the -r flag or by setting the
repositories managed by this application in your config files:
config :adah, ecto_repos: [...]
The configuration may be an empty list if it does not define any repo.
** (Protocol.UndefinedError) protocol Enumerable not implemented for :ok
(elixir) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) lib/enum.ex:116: Enumerable.reduce/3
(elixir) lib/enum.ex:1486: Enum.reduce/3
(elixir) lib/enum.ex:609: Enum.each/2
(mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
My deps are:
phoenix_ecto: 3.0.0-rc.0
ecto: 2.0.0-rc.0
...
My config files have the following lines:
dev.ex:
# Configure your database
config :adah, Adah.Repo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "adah_dev",
hostname: "localhost",
pool_size: 10
test.ex:
# Configure your database
config :adah, Adah.Repo,
adapter: Ecto.Adapters.Postgres,
username: System.get_env("POSTGRES_USER") || "postgres",
password: System.get_env("POSTGRES_PASSWORD") || "postgres",
database: System.get_env("POSTGRES_DB") || "adah_test",
hostname: System.get_env("POSTGRES_HOST") || "localhost",
pool: Ecto.Adapters.SQL.Sandbox
And I have no such errors while running tests or serving pages in dev environment, only when I run mix ecto.migrate.
When I use {:ecto, "== 2.0.0-beta.2", :phoenix_ecto, "== 3.0.0-beta.2"} everything works as excepted!
defp filter_rules(query, filter) do
p_gop = filter |> Map.get("groupOp")
if p_gop == "AND" do
IO.inspect "Ooption AND"
query |> where([p], p.age > 78) |> where([p], p.age < 80)
else
IO.inspect "Ooption OR"
query |> or_where([p], p.age > 78) |> or_where([p], p.age < 80)
end
end
The first time works well
Option AND
[debug] QUERY OK source="employee" db=9.6ms decode=0.2ms
SELECT h0.`age`, h0.`inserted_at`, h0.`updated_at`
FROM `employee` AS h0 WHERE (h0.`age` > 78)
AND (h0.`age` < 80) LIMIT ? OFFSET ? [50, 0]
The second time when switching to the option "OR", remains in "AND"
Option OR
[debug] QUERY OK source="employee" db=9.6ms decode=0.2ms
SELECT h0.`age`, h0.`inserted_at`, h0.`updated_at`
FROM `employee` AS h0 WHERE (h0.`age` > 78)
AND (h0.`age` < 80) LIMIT ? OFFSET ? [50, 0]
if first out "OR" always remains in OR
I was wondering why primary keys are required on this spot
defp form_for_hidden(%{__struct__: _} = data) do
# Since they are primary keys, we should ignore nil values.
for {k, v} <- Ecto.primary_key(data), v != nil, do: {k, v}
end
defp form_for_hidden(_), do: []
We use embedded_schema
to store subdocuments inside single Mongo Object, with schema like the following:
embedded_schema do
field :name, :string
field :desc, :string
field :map_sprite, :string
embeds_one :attributes, Fatespinner.Character.Attributes
belongs_to :account, Fatespinner.Account
has_many :game_character, Fatespinner.GameCharacter
timestamps
end
where Fatespinner.Character.Attributes
have to look like:
@primary_key false
embedded_schema do
field :strength, :integer, default: @default_attribute_value, primary_key: true
field :dexterity, :integer, default: @default_attribute_value
field :health, :integer, default: @default_attribute_value
field :intelligence, :integer, default: @default_attribute_value
field :wits, :integer, default: @default_attribute_value
field :will, :integer, default: @default_attribute_value
field :charisma, :integer, default: @default_attribute_value
field :communication, :integer, default: @default_attribute_value
field :empathy, :integer, default: @default_attribute_value
end
This dummy primary key looks annoying, because it's set only not to trigger "missing primary key error" while editing nested embedded_schema with inputs_for
.
Hi, could you add a tag for 0.6.0 too?
I'm starting with Phoenix framework and trying to get my hands on - https://github.com/gitter-badger/phoenix-starter
When I try to mix ecto.create
I get following error -
** (ArgumentError) argument error
:erlang.byte_size(nil)
lib/ecto/adapters/postgres.ex:83: Ecto.Adapters.Postgres.storage_up/1
lib/mix/tasks/ecto.create.ex:34: anonymous fn/2 in Mix.Tasks.Ecto.Create.run/1
(elixir) lib/enum.ex:604: Enum."-each/2-lists^foreach/1-0-"/2
(elixir) lib/enum.ex:604: Enum.each/2
(mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
(elixir) lib/code.ex:363: Code.require_file/2
I'm clueless at this point about how to fix this. I have {:phoenix_ecto, "~> 2.0"}
dependency.
Hey there,
I'm not sure where to file this (my internal candidate list phoenix, plug and this) but for our phoenix application when the request fails due to an Ecto.CastError or similiar then nothing is put in the log, as opposed to when things went well. I.e.
2017-02-03 16:08:18.993 request_id=iaii05j9d9oq826v34ob52rbfvf9b4d6 [info] GET /api/resource/946
2017-02-03 16:08:19.007 request_id=iaii05j9d9oq826v34ob52rbfvf9b4d6 [info] Sent 200 in 13ms
2017-02-03 16:08:57.679 request_id=ck7hpthcp6drk347c537c9l48fhdm10r [info] GET /api/resource/946
2017-02-03 16:09:44.994 request_id=4ehom7l2k2g5nmonjioj5fr1v96eeume [info] GET /api/resource/946
The first request is successful, and nicely tells me that it was successful. The next 2 requests I altered the data to be garbage (text instead of a time) and then we don't see what answer was sent back to the client.
I think the definition of the status codes happens here in plug.ex while the error_handler in plug captures it and I guess the skipping might happen for the non 500 status in the translator - but I'm not sure.
Also I believe the logging happens in the Plug.Logger which is then skipped or something.
So I guess questions are:
Thanks for all your work and heart ๐ โค๏ธ
edit: I had seen elixir-plug/plug#365 but to my understanding that is more focused on that it's hard to actually catch the error from cowboy
(* I'm sorry. I can't speak english )
$ mix -v
Mix 1.2.4
$ mix deps
* connection 1.0.2 (Hex package) (mix)
locked at 1.0.2 (connection)
ok
* fs 0.9.1 (Hex package) (rebar)
locked at 0.9.2 (fs)
ok
* gettext 0.11.0 (Hex package) (mix)
locked at 0.11.0 (gettext)
ok
* ranch 1.2.1 (Hex package) (rebar)
locked at 1.2.1 (ranch)
ok
* poolboy 1.5.1 (Hex package) (rebar)
locked at 1.5.1 (poolboy)
ok
* decimal 1.1.2 (Hex package) (mix)
locked at 1.1.2 (decimal)
ok
* poison 1.5.2 (Hex package) (mix)
locked at 1.5.2 (poison)
ok
* db_connection 0.2.5 (Hex package) (mix)
locked at 0.2.5 (db_connection)
ok
* cowlib 1.0.2 (Hex package) (rebar)
locked at 1.0.2 (cowlib)
ok
* cowboy 1.0.4 (Hex package) (rebar)
locked at 1.0.4 (cowboy)
ok
* plug 1.1.4 (Hex package) (mix)
locked at 1.1.4 (plug)
ok
* phoenix_html 2.5.1 (Hex package) (mix)
locked at 2.5.1 (phoenix_html)
ok
* phoenix 1.1.4 (Hex package) (mix)
locked at 1.1.4 (phoenix)
ok
* phoenix_live_reload 1.0.5 (Hex package) (mix)
locked at 1.0.5 (phoenix_live_reload)
ok
* mariaex 0.7.4 (Hex package) (mix)
locked at 0.7.4 (mariaex)
ok
* ecto 1.1.4 (Hex package) (mix)
locked at 1.1.4 (ecto)
ok
* phoenix_ecto 2.0.1 (Hex package) (mix)
locked at 2.0.1 (phoenix_ecto)
ok
$ mix phoenix.gen.html User users name:string
...
...
$ mix ecto.migrate
$ mix phoenix.gen.html Movie movies user_id:references:users title:string
...
...
$ mix ecto.migrate
$ mix ecto.rollback
15:39:41.618 [info] == Running EctoDropTest.Repo.Migrations.CreateMovie.change/0 backward
15:39:41.618 [info] drop index movies_user_id_index
** (Mariaex.Error) (1553): Cannot drop index 'movies_user_id_index': needed in a foreign key constraint
(ecto) lib/ecto/adapters/sql.ex:185: Ecto.Adapters.SQL.query!/5
(ecto) lib/ecto/adapters/mysql.ex:85: anonymous fn/4 in Ecto.Adapters.MySQL.execute_ddl/3
(elixir) lib/enum.ex:1473: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/adapters/mysql.ex:85: Ecto.Adapters.MySQL.execute_ddl/3
(ecto) lib/ecto/migration/runner.ex:89: anonymous fn/2 in Ecto.Migration.Runner.flush/0
(elixir) lib/enum.ex:1473: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto) lib/ecto/migration/runner.ex:87: Ecto.Migration.Runner.flush/0
(stdlib) timer.erl:181: :timer.tc/2
(ecto) lib/ecto/migration/runner.ex:26: Ecto.Migration.Runner.run/6
(ecto) lib/ecto/migrator.ex:121: Ecto.Migrator.attempt/6
(ecto) lib/ecto/migrator.ex:101: anonymous fn/4 in Ecto.Migrator.do_down/4
(ecto) lib/ecto/migrator.ex:227: anonymous fn/4 in Ecto.Migrator.migrate/4
(elixir) lib/enum.ex:1088: Enum."-map/2-lists^map/1-0-"/2
(ecto) lib/mix/tasks/ecto.rollback.ex:64: anonymous fn/4 in Mix.Tasks.Ecto.Rollback.run/2
(elixir) lib/enum.ex:604: Enum."-each/2-lists^foreach/1-0-"/2
(elixir) lib/enum.ex:604: Enum.each/2
(mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
Is this a known issue or there is something wrong with my app?
Thank you!!
I have v3 declared as a dependency in my project, {:phoenix_ecto, "~> 3.0"}
, but when trying to compile it get a CaseClauseError
.
==> phoenix_ecto
Compiled lib/phoenix_ecto.ex
Compiled lib/phoenix_ecto/plug.ex
Compiled lib/phoenix_ecto/sql/sandbox.ex
Compiled lib/phoenix_ecto/html.ex
Generated phoenix_ecto app
** (CaseClauseError) no case clause matching: {:error, :tokens}
(kernel) file.erl:1368: :file.consult_stream/3
(kernel) file.erl:978: :file.consult/1
(mix) lib/mix/dep/elixir_scm.ex:20: Mix.Dep.ElixirSCM.read/1
(mix) lib/mix/tasks/loadpaths.ex:67: Mix.Tasks.Loadpaths.load_project/2
(mix) lib/mix/tasks/loadpaths.ex:30: Mix.Tasks.Loadpaths.run/1
(mix) lib/mix/tasks/app.start.ex:36: Mix.Tasks.App.Start.run/1
(mix) lib/mix/tasks/run.ex:63: Mix.Tasks.Run.run/1
(mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2
here is my complete dependency list.
defp deps do
[{:phoenix, "~> 1.2.0"},
{:mariaex, ">= 0.0.0"},
{:phoenix_ecto, "~> 3.0"},
{:phoenix_html, "~> 2.4"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:cowboy, "~> 1.0"},
{:memcache_client, "~> 1.0.0"},
{:credo, "~> 0.4", only: [:dev, :test]}]
end
I ran into a possible bug when using inputs_for
with cast_assoc
and custom changesets. This is a standard many-to-many association.
When I specify a changeset with a different name (than changeset) in cast_assoc
(for example, cast_assoc(:foo, with: :bar_changeset)
), the form fails with this error (see stack trace below):
no function clause matching in Phoenix.HTML.FormData.Ecto.Changeset.to_changeset/4
Here are my models:
defmodule App.Organisation do
schema "organisations" do
has_many :memberships, App.Membership
has_many :users, through: [:memberships, :user]
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name])
|> cast_assoc(:memberships, with: :registration_changeset)
end
end
defmodule App.Membership do
schema "organisation_users" do
belongs_to :organisation, App.Organisation
belongs_to :user, App.User
end
def registration_changeset(struct, params \\ %{}) do
struct
|> cast(params, [:role])
|> cast_assoc(:user, with: :registration_changeset)
end
end
defmodule App.User do
schema "users" do
has_many :memberships, App.Membership
has_many :organisations, through: [:memberships, :organisation]
end
def registration_changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name, :email, :password])
end
end
Pay attention to cast_assoc(:memberships, with: :registration_changeset)
and cast_assoc(:user, with: :registration_changeset)
in Organisation and Membership respectively. When I rename my registration_changeset
functions to changeset
, and remove the with: :registration_changeset
from cast_assoc
, everything works normally.
Here's my view:
<%= form_for @changeset, registration_path(@conn, :create), fn f -> %>
<div class="form-group">
<%= label f, :name %>
<%= text_input f, :name, class: "form-control" %>
<%= error_tag f, :name %>
</div>
<div class="form-group">
<%= inputs_for f, :memberships, fn membership -> %>
<%= inputs_for membership, :user, fn user -> %>
<div class="form-group">
<%= label user, :name %>
<%= text_input user, :name, class: "form-control" %>
<%= error_tag user, :name %>
</div>
<% end %>
<% end %>
</div>
<%= submit "Create", class: "btn btn-primary" %>
<% end %>
Here's a stack trace:
[error] #PID<0.3754.0> running App.Endpoint terminated
Server: localhost:4000 (http)
Request: GET /registrations/new
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Phoenix.HTML.FormData.Ecto.Changeset.to_changeset/4
(phoenix_ecto) lib/phoenix_ecto/html.ex:207: Phoenix.HTML.FormData.Ecto.Changeset.to_changeset(%App.Membership{__meta__: #Ecto.Schema.Metadata<:built, "organisation_users">, id: nil, inserted_at: nil, organisation: #Ecto.Association.NotLoaded<association :organisation is not loaded>, organisation_id: nil, role: nil, updated_at: nil, user: %App.User{__meta__: #Ecto.Schema.Metadata<:built, "users">, email: nil, id: nil, inserted_at: nil, memberships: #Ecto.Association.NotLoaded<association :memberships is not loaded>, name: nil, organisations: #Ecto.Association.NotLoaded<association :organisations is not loaded>, password: nil, password_hash: nil, updated_at: nil}, user_id: nil}, nil, App.Membership, :registration_changeset)
(phoenix_ecto) lib/phoenix_ecto/html.ex:78: anonymous fn/8 in Phoenix.HTML.FormData.Ecto.Changeset.to_form/4
(elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
(phoenix_ecto) lib/phoenix_ecto/html.ex:76: Phoenix.HTML.FormData.Ecto.Changeset.to_form/4
(phoenix_html) lib/phoenix_html/form.ex:270: Phoenix.HTML.Form.inputs_for/4
(App) web/templates/registration/new.html.eex:16: anonymous fn/1 in App.RegistrationView.new.html/1
(phoenix_html) lib/phoenix_html/form.ex:236: Phoenix.HTML.Form.form_for/4
(App) web/templates/registration/new.html.eex:6: App.RegistrationView."new.html"/1
(App) web/templates/layout/registration.html.eex:19: App.LayoutView."registration.html"/1
(phoenix) lib/phoenix/view.ex:335: Phoenix.View.render_to_iodata/3
(phoenix) lib/phoenix/controller.ex:642: Phoenix.Controller.do_render/4
(App) web/controllers/registration_controller.ex:1: App.RegistrationController.action/2
(App) web/controllers/registration_controller.ex:1: App.RegistrationController.phoenix_controller_pipeline/2
(App) lib/App/endpoint.ex:1: App.Endpoint.instrument/4
(App) lib/phoenix/router.ex:261: App.Router.dispatch/2
(App) web/router.ex:1: App.Router.do_call/2
(App) lib/App/endpoint.ex:1: App.Endpoint.phoenix_pipeline/1
(App) lib/plug/debugger.ex:123: App.Endpoint."call (overridable 3)"/2
(App) lib/App/endpoint.ex:1: App.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:15: Plug.Adapters.Cowboy.Handler.upgrade/4
I'm using Phoenix v1.2.1.
I have the issue like this ecto's issue with phoenix_ecto:
elixir-ecto/ecto#1678
Pls advise. How to use 'on' query with paramater
from i in query,
left_join: v in assoc(i, :votes)
on: v.user_id = ^user_id
How to make it works ?
def deps do
[{:phoenix_ecto, "~> 3.1.0-rc.0"}]
end
error message
Unchecked dependencies for environment dev:
* phoenix_ecto (Hex package)
the dependency does not match the requirement "~> 3.1.0-rc.0", got "3.0.1"
** (Mix) Can't continue due to errors on dependencies
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.