2016-09-18 44 views
1

我学习框架凤凰。 是将存储在云存储中的图像模型。在创建图像时,我计算文件的哈希值,并将其作为:名称。我做了一个模型,控制器和视图。但我不明白为什么我收到一个错误:phoenix undefined function changeset/3

== Compilation error on file web/models/image.ex == 
** (CompileError) web/models/image.ex:26: undefined function changeset/3 
    (stdlib) lists.erl:1338: :lists.foreach/2 
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6 
    (elixir) lib/kernel/parallel_compiler.ex:116: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1 

我查阅了所有的代码,但是没有找到,我打电话Image.changeset有三个参数的地方。 我image.ex:

defmodule Blog.Image do 
    use Blog.Web, :model 

    schema "images" do 
    field :name, :string 
    field :original_name, :string 
    field :filename, :string, virtual: true 

    timestamps 
    end 

    @required_fields ~w(
    name 
    original_name 
    filename 
) 
    @optional_fields ~w() 

    def changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, @required_fields, @optional_fields) 
    end 

    def create_changeset(struct, params \\ %{}) do 
    struct 
    |> changeset(struct, params) 
    |> generate_name_hash 
    end 

    defp generate_name_hash(changeset) do 
    put_change(changeset, :name, gen_hash_name(changeset[:filename])) 
    end 

    defp gen_hash_name(filename) do 
    hash_name = :crypto.hash(:sha256, File.read(filename)) 
    |> Base.encode16 
    "/"<>slice(hash_name, 0, 2)<>"/"<>slice(hash_name, 2, 2)<>"/"<>slice(hash_name, 4, 2) 
    end 

end 

我image_controller.ex:

defmodule Blog.ImageController do 
    use Blog.Web, :controller 
    plug Addict.Plugs.Authenticated when action in [:new, :create] 

    def new(conn, _params) do 
    changeset = Blog.Image.changeset(%Blog.Image{}) 
    render conn, "new.html", changeset: changeset 
    end 

    def create(conn, %{"image" => image_params}) do 
    full_image_params = %{filename: image_params["image"].path, original_name: image_params["image"].filename} 
    changeset = Blog.Image.create_changeset(%Blog.Image{}, full_image_params) 
    case Blog.Repo.insert(changeset) do 
     {:ok, image} -> 
     conn 
     |> put_flash(:info, "Image created successfully.") 
     |> redirect(to: image_path(conn, :show, image)) 
     {:error, changeset} -> 
     render(conn, "new.html", changeset: changeset) 
    end 
    end 
end 

我new.html.eex:

<%= form_for @changeset, image_path(@conn, :create), [role: "form", multipart: true], fn f -> %> 
    <div class="form-group"> 
    <%= label f, :image, class: "control-label" %> 
    <%= file_input f, :image, class: "form-control" %> 
    <%= error_tag f, :image %> 
    </div> 
    <div class="container"> 
    <div class="form-group"> 
     <%= submit "Submit", class: "btn btn-default" %> 
    </div> 
    </div> 
<% end %> 

回答

2

我相信这一点:

def create_changeset(struct, params \\ %{}) do 
    struct 
    |> changeset(struct, params) 
    |> generate_name_hash 
    end 

应该是

def create_changeset(struct, params \\ %{}) do 
    struct 
    |> changeset(params) 
    |> generate_name_hash 
    end 

因为|>运算符会将其左侧的所有内容作为函数的第一个参数传递给右侧。所以你基本上在做changeset(struct, struct, params)

0

堆栈跟踪告诉你你的错误的确切位置: ** (CompileError) web/models/image.ex:26: undefined function changeset/3

我相信你正在尝试使用cast函数,因为changeset函数本身并不存在于Ecto changesets中。此外,cast有三个arity,所以你错过了一个参数。

更改此线26:

def create_changeset(struct, params \\ %{}) do 
    struct 
    |> changeset(struct, params) 
    |> generate_name_hash 
end 

这样:

def create_changeset(struct, params \\ %{}) do 
    struct 
    |> cast(params, [:name, :original_name, :filename]) #<---- 3rd arg. = 'allowed' 
    |> generate_name_hash 
end 

cast功能需要三个参数cast(data, params, allowed)。所有未明确允许的参数都将被忽略。

就像Mchl说的那样,函数的结果被传递给管道操作中下一个函数的第一个参数(在这个特定的文章中,你不需要明确地通过struct)。

相关问题