Change a changeset - phoenix-framework

I don't understand how I can change the values of a given changeset.
Setup
mix phoenix.new shop
cd shop
mix ecto.create
mix phoenix.gen.html Product products name price:integer
mix ecto.migrate
web/router.ex
[...]
scope "/", Shop do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/products", ProductController
end
[...]
The Problem
I start the IEX and create a new changeset:
iex -S mix phoenix.server
iex(1)> alias Shop.Product
iex(2)> changeset = Product.changeset(%Product{price: 1})
#Ecto.Changeset<action: nil, changes: %{},
errors: [name: {"can't be blank", [validation: :required]}],
data: #Shop.Product<>, valid?: false>
How can I change that given changeset now? The following code doesn't work:
iex(3)> changeset = Product.changeset(changeset, %{name: "Orange"})
#Ecto.Changeset<action: nil, changes: %{name: "Orange"},
errors: [name: {"can't be blank", [validation: :required]}],
data: #Shop.Product<>, valid?: false>
Because of the errors I can't do a Shop.Repo.insert(changeset) now.
I know that in this specific example I could change the iex(2) line to get the changeset I want. But I'd like to know how to manipulate a changeset after it's been created.

Product.changeset(changeset.data, Map.merge(changeset.changes, %{name: "Orange"})) does the trick. Thanks to Dogbert.
$ iex -S mix phoenix.server
iex(1)> alias Shop.Product
Shop.Product
iex(2)> changeset = Product.changeset(%Product{price: 1})
#Ecto.Changeset<action: nil, changes: %{},
errors: [name: {"can't be blank", [validation: :required]}],
data: #Shop.Product<>, valid?: false>
iex(3)> changeset = Product.changeset(changeset.data, Map.merge(changeset.changes, %{name: "Orange"}))
#Ecto.Changeset<action: nil, changes: %{name: "Orange"}, errors: [],
data: #Shop.Product<>, valid?: true>
iex(4)>

Related

botium-cli emulator does not work with the rasa connector

When I try to start the emulator for my rasa bot, I get this error. The rasa endpoint url works perfectly fine when I send it a request with curl.
$ botium-cli emulator
Error: Start failed: undefined
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\src\containers\plugins\SimpleRestContainer.js:170:25
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:2955:19
at wrapper (C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:268:20)
at iterateeCallback (C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:413:21)
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:321:20
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:2953:17
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\src\containers\plugins\SimpleRestContainer.js:130:17
Here's the botium.json
{
"botium": {
"Capabilities": {
"PROJECTNAME": "My Botium Project",
"CONTAINERMODE": "rasa",
"RASA_MODE": "DIALOG_AND_NLU",
"SIMPLEREST_STRICT_SSL" : "false",
"RASA_ENDPOINT_URL": "https://example.com/webhooks/rest/webhook"
},
"Sources": {},
"Envs": {}
}
}
Here's the output from the emulator with the verbose tag.
Still does not work, maybe it has to do something with the way botium connects to the bot?
$ botium-cli emulator --verbose
2021-03-05T08:17:32.230Z botium-cli Using Botium configuration file ./botium.json
2021-03-05T08:17:32.240Z botium-cli-emulator command options: {
_: [ 'emulator' ],
verbose: true,
v: true,
convos: [ '.' ],
C: [ '.' ],
config: './botium.json',
c: './botium.json',
ui: 'console',
'$0': '..\\..\\AppData\\Roaming\\npm\\node_modules\\botium-cli\\bin\\botium-cli.js'
}
2021-03-05T08:17:32.573Z botium-core-BotDriver Loaded Botium configuration files C:\Users\shivam.sinha\Desktop\rasa check\botium.json
2021-03-05T08:17:33.085Z botium-core-BotDriver Build - Botium Core Version: 1.11.1
2021-03-05T08:17:33.087Z botium-core-BotDriver Build - Capabilites: {
PROJECTNAME: 'My Botium Project',
TESTSESSIONNAME: 'Botium Test Session',
TESTCASENAME: 'Botium Test Case',
TEMPDIR: 'botiumwork',
CLEANUPTEMPDIR: true,
WAITFORBOTTIMEOUT: 10000,
SIMULATE_WRITING_SPEED: false,
SIMPLEREST_PING_RETRIES: 6,
SIMPLEREST_PING_TIMEOUT: 10000,
SIMPLEREST_PING_VERB: 'GET',
SIMPLEREST_PING_UPDATE_CONTEXT: true,
SIMPLEREST_STOP_RETRIES: 6,
SIMPLEREST_STOP_TIMEOUT: 10000,
SIMPLEREST_STOP_VERB: 'GET',
SIMPLEREST_START_RETRIES: 6,
SIMPLEREST_START_TIMEOUT: 10000,
SIMPLEREST_START_VERB: 'GET',
SIMPLEREST_POLL_VERB: 'GET',
SIMPLEREST_POLL_INTERVAL: 1000,
SIMPLEREST_POLL_UPDATE_CONTEXT: true,
SIMPLEREST_METHOD: 'GET',
SIMPLEREST_IGNORE_EMPTY: true,
SIMPLEREST_TIMEOUT: 10000,
SIMPLEREST_EXTRA_OPTIONS: {},
SIMPLEREST_STRICT_SSL: false,
SIMPLEREST_INBOUND_UPDATE_CONTEXT: true,
SIMPLEREST_CONTEXT_MERGE_OR_REPLACE: 'MERGE',
SCRIPTING_TXT_EOL: '\n',
SCRIPTING_XLSX_EOL_WRITE: '\r\n',
SCRIPTING_XLSX_HASHEADERS: true,
SCRIPTING_CSV_SKIP_HEADER: true,
SCRIPTING_CSV_QUOTE: '"',
SCRIPTING_CSV_ESCAPE: '"',
SCRIPTING_NORMALIZE_TEXT: true,
SCRIPTING_ENABLE_MEMORY: false,
SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: false,
SCRIPTING_MATCHING_MODE: 'wildcardIgnoreCase',
SCRIPTING_UTTEXPANSION_MODE: 'all',
SCRIPTING_UTTEXPANSION_RANDOM_COUNT: 1,
SCRIPTING_UTTEXPANSION_NAMING_MODE: 'justLineTag',
SCRIPTING_UTTEXPANSION_NAMING_UTTERANCE_MAX: '16',
SCRIPTING_MEMORYEXPANSION_KEEP_ORIG: false,
ASSERTERS: [],
LOGIC_HOOKS: [],
USER_INPUTS: [],
SECURITY_ALLOW_UNSAFE: true,
CONTAINERMODE: 'rasa',
RASA_MODE: 'DIALOG_AND_NLU',
RASA_ENDPOINT_URL: 'https://10.60.31.102:8080/webhooks/rest/webhook',
CONFIG: './botium.json'
}
2021-03-05T08:17:33.087Z botium-core-BotDriver Build - Sources : { LOCALPATH: '.', GITPATH: 'git', GITBRANCH: 'master', GITDIR: '.' }
2021-03-05T08:17:33.087Z botium-core-BotDriver Build - Envs : { IS_BOTIUM_CONTAINER: true }
2021-03-05T08:17:33.274Z botium-connector-PluginConnectorContainer-helper Botium plugin botium-connector-rasa loaded. Plugin version is 0.0.7
Error: Start failed: undefined
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\src\containers\plugins\SimpleRestContainer.js:170:25
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:2955:19
at wrapper (C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:268:20)
at iterateeCallback (C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:413:21)
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:321:20
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\node_modules\async\dist\async.js:2953:17
at C:\Users\shivam.sinha\AppData\Roaming\npm\node_modules\botium-core\src\containers\plugins\SimpleRestContainer.js:130:17
The RASA_ENDPOINT_URL capability has to point to the base URL of your Rasa server - without the /webhooks/rest/webhook path. Botium will build up it's own full url endpoint path based on the RASA_MODE capability:
NLU_INPUT => /model/parse is appended
REST_INPUT => /webhooks/rest/webhook/ is appended
{
"botium": {
"Capabilities": {
"PROJECTNAME": "Botium Project Rasa NLU",
"CONTAINERMODE": "rasa",
"RASA_MODE": "NLU_INPUT",
"RASA_ENDPOINT_URL": "https://demo.botiumbox.com/rasa-demo/"
}
}
}

Ruby aws device farm throwing argument error when calling schedule_run method

I'm trying to schedule a run using the aws device farm sdk, I have followed the documentation, however, every time I call the schedule_run method I get this error:
Aws::DeviceFarm::Errors::ArgumentException: Missing or unprocessed resources
This is the method from where I'm calling schedule_run:
def schedule_run
aws_client.schedule_run({
project_arn: ANDROID_PROJECT_ARN, # required
app_arn: get_uploads_by_name(ANDROID_APP, 'ANDROID_APP').arn,
device_pool_arn: get_device_pool_by_name('Android test decive pool').arn,
device_selection_configuration: nil,
name: "test_run",
test: { # required
type: "APPIUM_RUBY",
test_package_arn: get_uploads_by_name(TEST_SUITE, 'APPIUM_RUBY_TEST_PACKAGE').arn,
test_spec_arn: get_uploads_by_name('aws_android_4.yml', 'APPIUM_RUBY_TEST_SPEC').arn,
filter: nil,
parameters: nil
},
configuration: {
extra_data_package_arn: nil,
network_profile_arn: get_network_profile_by_name('Full').arn,
locale: "en_US",
location: {
latitude: 47.6204, # required
longitude: 122.3491 # required
},
vpce_configuration_arns: nil,
customer_artifact_paths: {
ios_paths: nil,
android_paths: nil,
device_host_paths: %w[/tmp/allure-results /tmp/screenshots]
},
radios: {
wifi: true,
bluetooth: false,
nfc: true,
gps: true
},
auxiliary_apps: nil,
billing_method: "UNMETERED" # accepts METERED, UNMETERED
},
execution_configuration: {
job_timeout_minutes: 150,
accounts_cleanup: false,
app_packages_cleanup: false,
video_capture: false,
skip_app_resign: false
}
})
end
The exception Missing or unprocessed resources typically means that there was an issue with one of your uploads. Use the GetUpload on of your uploads to see what went wrong.

Need Help Unit Testing with Rails 5 for Update Action Always Fail on assert_equals

i want to test an update action in my rails project. The function is running well, but when i try to unit-test it's always fail. Can you help this?
i'm new with ruby and unit-testing. i've tried with any documentation it still not solve this test.
this is my Content Controller function that i want to test, i use clearance for auth
before_action :require_login
def update
#content = Content.find(params[:id])
if #content.update(content_params)
flash[:notice] = 'success'
redirect_back fallback_location: root_path
else
flash[:notice] = 'fail'
redirect_back fallback_location: root_path
end
end
this is my Content Fixture
one:
id: '1'
about: 'about content'
privacy: 'privacy content'
terms: 'terms content'
this is my test_helper
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
require 'clearance/test_unit'
class ActiveSupport::TestCase
fixtures :all
end
class ActionDispatch::IntegrationTest
def sign_in_as_user
user = User.create!(email: "example#example.com", password: "letmein")
post session_url, params: {
session: {
email: user.email,
password: user.password
}
}
end
end
And this is my test code
test "should update content" do
sign_in_as_user
content = contents(:one)
put content_url(content), params: { about: { syarat: "updated about", privacy: "updated privacy", terms: "updated terms" } }
content.reload
assert_equal "updated about", content.about
assert_equal "updated privacy", content.privacy
assert_equal "updated terms", content.terms
end
Then i run the test rake test, this is the result
Failure:
ContentControllerTest#test_should_update_content [/Users/abc/Documents/PROJECT/Apps/test-app/test/controllers/content_controller_test.rb:20]:
--- expected
+++ actual
## -1 +1 ##
-"updated about"
+"about content"

KeyError in Plug connection or session

So I was getting the error below because I was trying to access the :id key. No surprise here. However, my actual question is why is the user placed inside the :session key? Is this Plug specific? I don't remember setting user to the key :session as you can see in the view below.
Error:
** (KeyError) key :id not found in:
%{
session: %ExampleApp.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "ka#example.com",
first_name: "keith",
id: 356,
inserted_at: #Ecto.DateTime<2016-08-25 00:56:51>,
last_name: "a.",
updated_at: #Ecto.DateTime<2016-08-25 00:56:51>,
username: "keith"
},
view_module: ExampleApp.SessionView,
view_template: "show.json"
}
View that caused error:
defmodule ExampleApp.SessionView do
use ExampleApp.Web, :view
def render("show.json", %{jwt: jwt, user: user, exp: exp}) do
%{
jwt: jwt,
exp: exp,
user: render_one(user, __MODULE__, "show.json")
}
end
def render("show.json", user) do
%{
id: user.id, #<------------------------------------------ HERE
username: user.username,
last_name: user.last_name,
first_name: user.first_name
}
end
I had to do the following to access the user's information:
...
def render("show.json", user) do
%{
id: user.session.id, #<------------------------------------------ HERE
username: user.session.username,
last_name: user.session.last_name,
first_name: user.session.first_name
}
end
Here's the controller if it helps:
defmodule ExampleApp.RegistrationController do
use ExampleApp.Web, :controller
alias ExampleApp.{Repo, User, SessionView}
def create(conn, %{"user" => user_params}) do
changeset = User.new_changeset(%User{}, user_params)
case Repo.insert(changeset) do
{:ok, user} ->
{:ok, jwt, claims} = user |> Guardian.encode_and_sign(:token)
exp = Map.get(claims, "exp")
conn
|> put_status(:created)
|> render(SessionView, "show.json", %{jwt: jwt, user: user, exp: exp})
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render("error.json", changeset: changeset)
end
end
end
What am I doing wrong here? Thank you in advance for your help.
However, my actual question is why is the user placed inside the :session key?
That's because render_one tries to guess the key name using the name of the view you passed. In this case, you passed SessionView, so the key to use for the model is inferred to be :session. If you instead want it to be in :user, you can pass as: :user:
def render("show.json", %{jwt: jwt, user: user, exp: exp}) do
%{
jwt: jwt,
exp: exp,
user: render_one(user, __MODULE__, "show.json", as: :user)
}
end
You can read more about this in the documentation for Phoenix.View.render_one/4.
...
render_one user, UserView, "show.html"
...
The underlying user is passed to the view and template as :user, which is inflected from the view name. The name of the key in assigns can be customized with the :as option:
render_one user, UserView, "show.html", as: :data
...

Ruby 2.3 - not comprehensible ArgumentError exception

I'm currently in the process of upgrading a project from ruby 1.9.3 to ruby 2.3.0 and there is one thing I can't wrap my head around concerning keyword arguments.
I have a method definition like so:
def icon(icon_name, opts = {})
# ...
end
I call that method like so:
icon(:info, class: 'info-popup', data: { content: 'content', variation: 'inverted' })
and get the exception
unknown keywords: class, data
So I looked at the documentation of method calling in ruby 2.3 and read up on keyword arguments and tried the following things:
def icon(icon_name, opts: {}); end
icon(:info, opts: { class: 'info-popup', data: { content: object.description, variation: 'inverted' } }
#=> unknown keyword: opts
def icon(icon_name, *+args); end
icon(:info, class: 'info-popup', data: { content: 'content', variation: 'inverted' })
#=> unknown keywords: class, data
def icon(icon_name, *opts, **_); end
icon(:info, class: 'info-popup', data: { content: 'content', variation: 'inverted' })
#=> unknown keywords: class, data
def icon(icon_name, class: nil, data: nil); end
icon(:info, class: 'info-popup', data: { content: 'content', variation: 'inverted' })
#=> unknown keywords: class, data
What am I missing here?
Also, to give a little perspective: I would like to call that icon method in many different ways, since underneath there can be many options used like size: :small, or disabled: true, etc. resulting in according CSS classes. So the minimum way of calling the method is icon(:name_of_icon), which means setting a hundred keyword params with nil as default value seems not very practical to me...
UPDATE
This is part of a rails project, and the method is defined in a SemanticHelper module. Inside the method looks like this:
def icon(icon_name, opts = {})
additional_classes = ''
# STATES
additional_classes << 'disabled ' if !!opts.delete(:disabled)
# VARIATIONS
additional_classes << 'circular ' if !!opts.delete(:circular)
additional_classes << 'square ' if !!opts.delete(:square)
additional_classes << 'inverted ' if !!opts.delete(:inverted)
additional_classes << 'basic ' if !!opts.delete(:basic)
additional_classes << 'link icon ' if !!opts.delete(:link)
additional_classes << "#{opts.delete(:color)} " if opts[:color]
size = opts.delete(:size)
additional_classes << "#{size} " if !!size
flipped_direction = opts.delete(:flipped)
additional_classes << "#{flipped_direction} flipped" if !!flipped_direction
rotated_direction = opts.delete(:rotated)
additional_classes << "#{rotated_direction} rotated" if !!rotated_direction
opts[:class] = "#{opts[:class]} #{additional_classes} #{icon_name} icon"
content_tag(:i, '', opts)
end
With your original method definition, just try wrapping your options hash in curly braces:
icon(:info, {class: 'info-popup', data: { content: 'content', variation: 'inverted' }})
You have a typo in second approach. Named parameters should be declared with double splat, not with *+:
▶ def icon(icon_name, **opts) ; puts opts.inspect ; end
#⇒ :icon
▶ icon :info, class: 'info-popup',
data: { content: 'content', variation: 'inverted' })
#⇒ {:class=>"info-popup",
#⇒ :data=>{:content=>"content", :variation=>"inverted"}}

Resources