no function clause matching in Ecto.Changeset.cast/4 - casting

I've been stuck with a casting error with naivedatetime. Could someone unlock me please?
This is the POST request i'm trying to do:
URL: http://localhost:4000/api/workingtimes/1
Body:
{
"start": "2019-08-21 07:27:00",
"end": "2020-09-20 07:27:00"
}
Here is my schema:
defmodule TimeManager.Workingtimes.Workingtime do
use Ecto.Schema
import Ecto.Changeset
schema "workingtimes" do
field :start, :naive_datetime
field :end, :naive_datetime
belongs_to :user, TimeManager.Users.User
timestamps()
end
#doc false
def changeset(workingtime, attrs) do
workingtime
|> cast(attrs, [:start, :end, :user_id])
|> validate_required([:start, :end, :user_id])
|> assoc_constraint(:user)
end
end
And here is my create function in the controller:
def create(conn, workingtime_params) do
with {:ok, %Workingtime{} = workingtime} <- Workingtimes.create_workingtime(workingtime_params) do
conn
|> put_status(:created)
|> put_resp_header("location", Routes.workingtime_path(conn, :show, workingtime))
|> render("workingtime.json", workingtime: workingtime)
end
end
finally here is my create_workingtime function in my workingtimes.ex
def create_workingtime(attrs \\ %{}) do
%{"start" => starttime, "end" => endtime, "user_id"=>user_id } = attrs
{:ok, naivestart} = NaiveDateTime.from_iso8601(starttime)
{:ok, naiveend} = NaiveDateTime.from_iso8601(endtime)
attrs = %{"start" => naivestart, "end"=>naiveend, "user_id"=>user_id}
Workingtime
|> Workingtime.changeset(attrs)
|> Repo.insert()
end
The error in the log is:
(exit) an exception was raised:
** (FunctionClauseError) no function clause matching in Ecto.Changeset.cast/4
(ecto 3.5.2) lib/ecto/changeset.ex:461: Ecto.Changeset.cast(TimeManager.Workingtimes.Workingtime, %{"end" => ~N[2020-10-21 19:45:24.879000], "start" => ~N[2020-10-21 19:45:24.879000], "user_id" => "1"}, [:start, :end, :user_id], [])
(time_manager 0.1.0) lib/time_manager/workingtimes/workingtime.ex:16: TimeManager.Workingtimes.Workingtime.changeset/2
(time_manager 0.1.0) lib/time_manager/workingtimes.ex:63: TimeManager.Workingtimes.create_workingtime/1
(time_manager 0.1.0) lib/time_manager_web/controllers/workingtime_controller.ex:16: TimeManagerWeb.WorkingtimeController.create/2
(time_manager 0.1.0) lib/time_manager_web/controllers/workingtime_controller.ex:1: TimeManagerWeb.WorkingtimeController.action/2
(time_manager 0.1.0) lib/time_manager_web/controllers/workingtime_controller.ex:1: TimeManagerWeb.WorkingtimeController.phoenix_controller_pipeline/2

Ecto.Changeset.cast/4 takes a schema struct as the first argument, not a schema module. In your create_workingtime/1 function, try changing to this:
%Workingtime{}
|> Workingtime.changeset(attrs)
|> Repo.insert()

Found out the issue, in the create_workingtime function it was: %Workingtime{} isntead of just Workingtime
def create_workingtime(attrs \\ %{}) do
%{"start" => starttime, "end" => endtime, "user_id"=>user_id } = attrs
{:ok, naivestart} = NaiveDateTime.from_iso8601(starttime)
{:ok, naiveend} = NaiveDateTime.from_iso8601(endtime)
attrs = %{"start" => naivestart, "end"=>naiveend, "user_id"=>user_id}
%Workingtime{}
|> Workingtime.changeset(attrs)
|> Repo.insert()
end

Related

what will be a better approach to StreamData when one has 2 maps?

The following property test is working fine, however, I think there should be a better and more efficient way of implementing this.
params in the following property will be something like this:
%{
"project_id" => "%&!XX!hLCfsS-dO_<fy?kpi4y=AEumQ$Xn:#.7Fl TnH~k>ZLB[q",
"task_id" => [
%{"asset_id" => 10, "tasks" => []},
%{"asset_id" => 10, "tasks" => []}
]
}
Property Testing:
property "bad project value" do
[user, project] = prepare()
user_gen = constant(%{id: user.id})
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = constant(%{"asset_id" => 10, "tasks" => []})
|> list_of(length: 2)
tasks_gen = constant("task_id")
|> map_of(tasks, length: 1)
check all project <- project_gen, task <- tasks_gen , user <- user_gen do
params = Map.merge(project, task)
res = ProjectTask.Save.save(params, user)
assert res == {:error, :not_found}
end
Factory.my_terms is the following:
def my_terms() do
one_of([string(:alphanumeric), string(:ascii), atom(:alphanumeric), integer(), binary()])
end
UPDATE
property "bad project value" do
[user, project] = prepare()
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = List.duplicate(%{"asset_id" => 10, "tasks" => []}, 2)
tasks = %{"tasks" => tasks}
check all project <- project_gen do
params = Map.merge(project, tasks)
res = ProjectTask.Save.save(params, %{id: user.id})
assert res == {:error, :not_found}
end
end

Elixir/Phoenix enum through tuple to replace paths

I'm parsing some HTML with Floki. And receive the following tuple:
{"html", [{"lang", "en"}],
[{"head", [],
[{"title", [], ["My App"]},
{"link", [{"rel", "stylesheet"}, {"href", "/css/app.css"}], []}]},
{"body", [],
[{"main", [{"id", "main_container"}, {"role", "main"}], []},
{"script", [{"src", "/js/app.js"}], [""]},
{"iframe",
[{"src", "/phoenix/live_reload/frame"}, {"style", "display: none;"}],
[]}]}]}
Is it possible to enumerate through all the elements, and for those that have href or src add full path to them? For example in this case replace them with: http://localhost/css/app.css and http://localhost/js/app.js
Here's one way you could do it using a recursive function.
defmodule HTML do
def use_full_path({el, attrs, children}) do
{el, update_attrs(attrs), Enum.map(children, &use_full_path/1)}
end
def use_full_path(string) do
string
end
defp update_attrs(attrs) do
Enum.map(attrs, fn {key, val} ->
if key in ["href", "src"] do
{key, "http://localhost" <> val}
else
{key, val}
end
end)
end
end
tree = {"html", [{"lang", "en"}],
[{"head", [],
[{"title", [], ["My App"]},
{"link", [{"rel", "stylesheet"}, {"href", "/css/app.css"}], []}]},
{"body", [],
[{"main", [{"id", "main_container"}, {"role", "main"}], []},
{"script", [{"src", "/js/app.js"}], [""]},
{"iframe",
[{"src", "/phoenix/live_reload/frame"}, {"style", "display: none;"}],
[]}]}]}
HTML.use_full_path(tree) |> IO.inspect

How to check existance and nil in single line for variable in ruby on rails

def import_update
require 'csv'
file = params[:file]
CSV.foreach(file.path, headers: true) do |row|
#prod = Spree::Product.find(row["id"])
#var = Spree::Variant.find_by(product_id: #prod.id)
Spree::Product.where(:id => row["id"]).update_all(:name => row["name"] if !row[name].nil?.present?, :meta_description => row["meta_description"], :shipping_category_id => row["shipping_category_id"], :description => row["description"], :meta_keywords => row["meta_keywords"], :tax_category_id => row["tax_category_id"], :available_on => row["available_on"], :deleted_at => row["deleted_at"], :promotionable => row["promotionable"], :meta_title => row["meta_title"], :featured => row["featured"], :supplier_id => row["supplier_id"])
end
end
I want check that row is present or not. if it is present then it updated when it is not null and condition is in single line because I want to apply this for all variable in updation statement.I wrote code above but showing error.
Try this:
params = ["name","meta_description","shipping_category_id","description","meta_keywords","tax_category_id","available_on","deleted_at","promotionable","meta_title","featured","supplier_id"
hash = {}
params.each do |param|
if row[param]
hash[param] = row[param]
end
end
Spree::Product.where(:id => row["id"]).update_attributes(hash)
This will let you keep your code dry.
EDIT:
What are these lines supposed to do?:
#prod = Spree::Product.find(row["id"])
#var = Spree::Variant.find_by(product_id: #prod.id)
I presume you don't have several entries with one ID. And your not using the objects that you retrieved in those two lines, so simply write the method like this:
def import_update
require 'csv'
file = params[:file]
params = ["name","meta_description","shipping_category_id","description","meta_keywords","tax_category_id","available_on","deleted_at","promotionable","meta_title","featured","supplier_id"]
CSV.foreach(file.path, headers: true) do |row|
hash = {}
params.each do |param|
if row[param]
hash[param] = row[param]
end
end
Spree::Product.find(row["id"]).update_all(hash)
end
end

Filtering/Pattern Matching in nested data structure

I am new to Elixir and still very confused with pattern matching.
[%{name: "Deutschland", code: "DE"}, %{name: "Frankreich", code: "FR"}]
def find_by_code([], _name), do: []
def find_by_code([h | t], query) do
if h[:code] == query do
IO.puts("MATCH")
IO.inspect(h)
else
IO.puts ("No match")
find_by_code(t, query)
end
end
Is that the best way to find the country by code?
You can pattern match as deep as you want:
def find_by_code([], _query),
do: nil # or whatever you want to mean "not found"
def find_by_code([%{code: query} = country|_t], query),
do: IO.inspect(country)
def find_by_code([_country|t], query),
do: find_by_code(t, query)
You can also use the Enum.find/3 with match?/2, which may be more readable (as suggested in another answer).
You could do it this way:
countries = [
%{name: "Deutschland", code: "DE"},
%{name: "Frankreich", code: "FR"}
]
Enum.find(countries, &match?(%{code: "FR"}, &1))
# %{code: "FR", name: "Frankreich"}
Elixir doesn't have built in pattern matching for trying to filter out certain items of a list based on their values.
You could write a pattern match to check individual items like so:
match_country_code = fn (%{:code => "DE"} = country) -> country
(_) -> nil
end
And then pass that to Enum.find:
lands = [
%{name: "Deutschland", code: "DE"},
%{name: "Frankreich", code: "FR"}
]
Enum.find(lands, &(match_country_code.(&1)))
# => %{code: "DE", name: "Deutschland"}
Or to generalize you could:
lands = [
%{name: "Deutschland", code: "DE"},
%{name: "Frankreich", code: "FR"}
]
find_by = fn (list, key, val) ->
Enum.find(list, &(Map.get(&1, key)==val))
end
find_by.(lands, :name, "DE")
#=> %{code: "DE", name: "Deutschland"}
Change find to filter and get a list of results:
lands = [
%{name: "Deutschland", code: "DE"},
%{name: "Germany", code: "DE"},
%{name: "Frankreich", code: "FR"}
]
filter_by = fn (list, key, val) ->
Enum.filter(list, &(Map.get(&1, key)==val))
end
filter_by.(lands, :code, "DE")
#=> [%{code: "DE", name: "Deutschland"}, %{code: "DE", name: "Germany"}]

Promotion/bubble-wrap TableScreen data

I'm stuck on this:
I need to populate data into my app.
I'm using Promotion for the very first time....
Without ProMotion I use to fetch the data in the init method
Now my code looks like below:
class Parties < ProMotion::TableScreen
attr_accessor :_cells
#news = []
include MyUiModules
title 'Yazarlar'
refreshable callback: :on_refresh,
pull_message: "Pull to refresh",
refreshing: "Refreshing data…",
updated_format: "Last updated at %s",
updated_time_format: "%l:%M %p"
def on_refresh
#MyItems.pull_from_server do |items|
##my_items = items
end_refreshing
#update_table_data
# end
end
def table_data
_cells = []
[{
title: nil,
cells: create_cells(_cells)
}]
end
def will_appear
Barbutton.create_bar(self)
set_attributes self.view, {
backgroundColor: hex_color("DBDBDB")
}
end
def go_to_next
App.delegate.slide_menu.show_menu
end
def create_cells(_cells)
BW::HTTP.get(URL) do |response|
json = BW::JSON.parse response.body.to_str
for line in json
_cells << { title: line["val_for_title"]}
end
end
_cells
end
end
Unfotunately this does return an empty array, and I can't figure out how to solve it.
Thx for your help
You can't do that because BW::HTTP.get is asynchronous !
Instead try something like this:
def on_init
#data = []
end
def table_data
[
{
title: nil,
cells: #data
}
]
end
def on_refresh
BW::HTTP.get(URL) do |response|
#data = []
json = BW::JSON.parse(response.body.to_str)
json.each do |hash|
#data << { title: hash["val_for_title"]}
end
update_table_data
end_refreshing
end
end
Hope it helps :-)