Reputation: 117
I'm really struggling to understand Contexts in Phoenix Elixir. I have three contexts, Auth
(contains User.ex
), Groups
(Circle.ex
), and Content
(ShareMark.ex
). Within each of those, there are schemas, users
, circles
, and sharemarks
respectively.
I'm trying to figure out how to use the pre-provided create_circle
outside of the Groups
context. Is there something a context is analogous to in Ruby?
Within content_test.ex
, I am trying to define the following
@valid_attrs %{circle: Groups.create_circle(%{name: "My test"}), url: "google.com", title: "Google"}
defmodule ShareMark.ContentTest do
use ShareMark.DataCase
alias ShareMark.Content
use ShareMark.Groups
describe "sharemarks" do
alias ShareMark.Content.ShareMark
@valid_attrs %{circle: Groups.create_circle(%{name: "Evan's test"}), url: "google.com", title: "Google"}
@update_attrs %{circle: Groups.create_circle(%{name: "Mike's test"}), url: "duckduckgo.com", title: "DuckDuckGo"}
@invalid_attrs %{circle: Groups.create_circle(%{name: "Bad test"})}
def sharemark_fixture(attrs \\ %{}) do
{:ok, sharemark} =
attrs
|> Enum.into(@valid_attrs)
|> Content.create_sharemark()
sharemark
end
...
end
Here is circle.ex
defmodule ShareMark.Groups.Circle do
use Ecto.Schema
import Ecto.Changeset
schema "circles" do
field :name, :string
field :creator_id, :id
many_to_many :members, ShareMark.Auth.User, join_through: "users_circles"
has_many :sharemarks, ShareMark.Content.ShareMark
timestamps()
end
@doc false
def changeset(circle, attrs) do
circle
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
But it is giving the following error:
** (CompileError) test/sharemark/content/content_test.exs:8: undefined function create_circle/1
Google is completely unhelpful, as Phoenix has so few questions asked about it. Sorry for such a novice question.
Upvotes: 0
Views: 141
Reputation: 75820
For starters, phoenix-framework does not force you to use Contexts, they're just a way of better organizing your code. This makes them slightly more confusing for beginners, compared to the File-Type First (FTF) structure of rails applications, but makes the code heirarchy much more easier to understand and manage in the long haul.
You can choose to use contexts or just put all modules together. Either way, whatever public functions you define are acessible from anywhere else in the app (as long as you use the correct module name to call them).
More resources on Contexts:
Now on to your actual code, there are two problems with it.
First, as @Paweł mentioned, you need to alias
your module or use the full name:
alias ShareMark.Groups
Second, you're calling Groups.create_circle
in a module attribute (@value
). Module attributes aren't like your regular "variables", they are resolved at compile-time. Meaning, in your case, they will try to write to the database before you even start your test suite.
To fix that, either move your initialization logic to your actual test or into ExUnit's setup/1
callback:
setup do
%{circle: Groups.create_circle(%{name: "Test Circle"}}
end
test "something", %{circle: circle} do
valid_attrs = %{circle: circle, url: "google.com", title: "Google"}
# assert something
end
Upvotes: 1
Reputation: 9649
In your test you have this line:
use ShareMark.Groups
this should be an alias
statement:
alias ShareMark.Groups
Upvotes: 2