#Change function argument at runtime inside decorator

12 messages · Page 1 of 1 (latest)

hexed raptor
#

Hello we are trying to validate params and then change the second argument
inside a decorator to the thingy that we cast using Ecto.Changeset
Does any one know how can this be accomplished, I've found a wall of knowledge
working with ast


def validate_params(module, body, %{args: [conn, params]}) do
  quote do
    result = unquote(module).validate(unquote(params))
    
    case result do
      {:ok, new_params} ->
        # Here I would like the new_params to be inside body
        unquote(body)
        
      [...]
    end
  end
end

@decorate validate_params(Params.That)
def all(conn, params) do
  # now params here are the result of Params.That.validate(params)
  [...]
end
tardy isle
#

Elixir is not python. This code is not idiomatic, and you're going to have continual problems with edge cases if you keep using this library.

#

if you want to validate params at runtime, you should write a function to do that, and then call that function

#

you're making something that's extremely simple into something that's extremely complex

#

an idiomatic solution would be:

def all(conn, params) do 
  case Params.That.validate(params) do 
    %Changeset{valid?: true} = changeset -> 
      # do something
    %Changeset{} = error -> 
      # show error
   end
end
hexed raptor
#

Thanks for the response, I agree with the complexity, event more with that thingy changing the parameters at runtime. I already have something along the lines of what you propesed, but I have that same thing repeated a million times. Searching for ways of avoiding to copy and paste decorators become a possibility. Maybe the only good solutions is what you wrote and thats it.

tardy isle
#

then put it in a module and call the resultant function

#

those are commonly called contexts in phoenix

hexed raptor
#

Im a bit lost, but at the end is something along this maybe

defmodule Thingy.That do
  @moduledoc false
  
  def validate(params) do
    # params validation!
  end
  
  def do_some_action(params, that) do
    case validate(params) do
      %Changeset{valid?: true} ->
        {:ok, "response"}
        
      %Changeset{valid?: false} = changeset ->
        {:error, changeset}
    end
  end
end

defmodule Thingy.Controller do
  @moduledoc false
  
  action_fallback Thingy.FallbackController
  
  def all(conn, params) do
    with {:ok, result} <- Thingy.That.do_some_action(params) do
      [...]
    end
  end
end

That it is really mimicking how the phoenix examples are with this kind of work

hexed raptor
#

Well at the end I got something like this

defmodule Thingy.Params.That do
  use Thingy.Params
  
  embeded_schema do
    [...]
  end
  
  def build(action, params) do
    action
    |> validate(params)
    |> apply_action(:insert)
  end
  
  def validate(:create, params) do
    %__MODULE__{}
    |> cast(params, __schema__(:fields))
    |> validate_this()
    |> validate_that()
  end
  
  def validate(:action, params) do
    %__MODULE__{}
    |> cast(params, [:that])
    |> validate_that()
  end
end

then in the controller just with <- and send the action for the params validation

tardy isle
#

Yes, do as little as possible in the controller.

#

Also, make an intermediate module where your business logic can go