This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-24
Channels
- # announcements (30)
- # asami (9)
- # babashka (37)
- # beginners (120)
- # calva (26)
- # cider (3)
- # clara (9)
- # clj-commons (7)
- # clj-kondo (17)
- # cljsrn (2)
- # clojure (32)
- # clojure-europe (56)
- # clojure-nl (1)
- # clojure-norway (13)
- # clojure-uk (4)
- # clojurescript (34)
- # conjure (1)
- # copenhagen-clojurians (8)
- # core-async (21)
- # cursive (2)
- # datahike (2)
- # datascript (5)
- # events (4)
- # fulcro (32)
- # graalvm (10)
- # heroku (3)
- # introduce-yourself (1)
- # jobs (2)
- # lsp (3)
- # luminus (1)
- # malli (8)
- # meander (15)
- # minecraft (1)
- # nrepl (2)
- # off-topic (57)
- # pathom (2)
- # polylith (35)
- # reagent (6)
- # reitit (8)
- # releases (1)
- # rewrite-clj (7)
- # shadow-cljs (21)
- # timbre (4)
- # tools-build (1)
- # tools-deps (33)
- # vrac (8)
Hi everyone!
I'm trying to understand the relation between keys and list. For example. This code return the keys from a map
(keys {:fname "frederico"}) ; it will return :fname
If I change the code to load it from a list, it will not work as expected.
(keys (:fname "frederico"))
Now if I send a list using quote to a function, I'm able to load the keys, even the args is a list. I even printed to validate it.
(defn fullname
[args]
(println args)
(let [{:keys [fname lname]} args]
(println "My fullname is" fname lname)))
(fullname '(:fname "Frederico" :lname "Benevides"))
So is there some specific reason why I'm able to use keys in this way ?
it needs to be (keys {:fname "frederico"}) keys needs a hashmap?
Thank you guys. I found a explanation from The Joy of Clojure. "Using a map to destructure a list of arguments causes the list to first be poured into a map collection before then being destructured as usual"
Just knowing the right keyword is all yeh need 😛 now got more research to do but first gotta do the sleep thing
> If I change the code to load it from a list, it will not work as expected.
> (keys (:fname "frederico"))
in this code, (:fname "fredirico")
is evaluated as a call to lookup :fname
, which always returns nil when the arg is not keyed (strings are not keyed)
lists are treated as calls unless somehow escaped or quoted
in context it looks like you actually had a seq (from args) (:fname (list :fname "frederico"))
Hello all. I have a quick question about macros. Is there any way to map over a list of parameters to the macro and add more functions before evaluation, effectively changing what the function does? For example, I envision a macro that maps something like (testing (+ 1 2) (+ 3 4)) to (do (cons 3 ('+ 1 2)) (cons 3 ('+ 3 4))? I have tried numerous variations(using 'body, body, @body) passing in [& body] to the macro, but when I try to map through it and add the symbols, I get numerous errors. I have also tried to google the answer to this question and read through clojure for the brave and true section on macros numerous times.
First thing that grabs me is the (cons 3 ('+ 1 2))
which is going to throw an error. You’re wanting (cons 3 '(+ 1 2))
.
(defmacro asdf
[body]
`(concat ~body '(5)))
(macroexpand (asdf '(+ 3 4)))
;=> (+ 3 4 5)
I’m using concat instead of cons, because cons will put it on the front, and you want this on the end
The backtick is basically like '
except it namespaces the symbols, which is very useful for not getting namespace issues later
Addition was a very confusing example to use. My bad. I just want to be able to essentially add things to the parameters pre evaluation
is it not true that, in that example, when you do ~body, body would get evaluated before you concat
Final bit of explaination: at the time of evaluation, body
is equal to '(+ 3 4)
, then you modify it as you would any clojure data structure
Ohhh I see
It’s been passed a data structure, it won’t do anything with that unless you call eval
somewhere
That means my error was elsewhere and I was totally off. Thus, I should be able to map through(if I had &body) and add something to each.
Yeah, I tried using it but still got confused by the output lol. I'm gonna take it slow. Thanks for the help!
I just realized, in order to it this way, you have to pass the parameters in as backticked right? There is no way to do it without that?
Currently I have
(defmacro testing [& body]
(map (fn [x#] (println x#)) ~body))`
and I get an exception
Oh wait I think I see what I did wrong.
Don't you need it to return a list that evaluates the map?
If you’re returning (map (fn …))`, then it’s going to literally return
(map (fn …))
before evaluating it
Yes it did haha
This is probably a decent spot for it, but in general most of the time you need a macro, a function will do
Yeah, i've read about that a lot before
I feel like everyone goes through the phase of wanting to use them everywhere lol
But I won't.
something that worked for my (YMMV) was to write macros without using ` - just using list / cons / concat etc. until I really understood what they were doing
backtick isn't "the macro syntax", it's a reader macro that splices values into list literals - something that's super useful when writing macros but also it can obfuscate what you are really doing
I've been following the book Web Development with Clojure 3rd edition and trying to deploy the app to Heroku. I got the app to show up on Heroku, but I can't figure out how to make the database work. Meaning I just see "loading messages..." on the home page and cannot log in or anything. I added the postgres plug-in following the steps from the book. Any advice? What changes do I need to make to my config file? I am also trying to run `heroku run lein run migrate` but having issues. It says it can't find a non empty config file, but I do have a dev-config.edn, probably with outdated/incorrect info in it.
There is a #heroku channel If you can share the code from your project, I can take a look (otherwise I would only be guessing). I dont have the book, but am familar with Heroku.
Thanks @U05254DQM I really appreciate it. I'm definitely having trouble understanding what to do with the config.edn file. From the book I had dev-config.edn but then it says to have a prod-config.edn. I know I probably need to change the database-url to be heroku credentials instead of my local ones, but I'm not sure how.
It will probably be me answering in the heroku channel, so may as well continue here
Oh ok. Thanks!
I usually just have the one config.edn file and place it in /resources
, using juxt/aero profiles to define values for different environments
If the book is suggesting different files, I assume those config.edn files are included via paths of leiningen profiles
The config.edn file doest seem to be on the class path, so wont be available to load (unless I missed something in the profies.clj file
Thanks I definitely forgot to add it to the class path. How do I do that? In project.clj I have :project/dev {:jvm-opts ["-Dconf=dev-config.edn" ]
would I replace dev-config.edn with just config.edn? I don't think I have a profiles.clj file should I add one?
Hmm, it seems the config is being loaded by mount using the kewl-app.config
namespace, although I am not following that bit yet
Ok interesting. It's based on a luminus template and I am not sure how all the details work unfortunately
Yes, there is a lot of learning in the luminus template. Looking at how it builds the uberjar, which is the thing that Heroku will ultimately run (via the Procfile), it sets a number of paths for resource files https://github.com/johnbradens/kewl-app-4/blob/main/project.clj#L68-L75
so the Heroku database connection should be in the env/prod/resources/config.edn
file I believe
Ohhhhh I see now. I found the file there!
It just says {:prod true :port 3000}
I'm assuming I must make some changes? And I'm curious why heroku run lein run migrate
said that it couldn't find a nonempty config file? :thinking_face:
Heroku has a DATABASE_URL environment variable that can be used to pull in the address of the database, eg. via System/getenv "DATABASE_URL"
https://practical.li/clojure-web-services/projects/leiningen/todo-app/postgres/environment-variables.html
Or you may need JDBC_DATABASE_URL` instead, it depends on the form of the connection URL required, this is also automatically created by Heroku when adding a database
Or is it ok to just say database_url: System/getenv "DATABASE_URL"
and then it automatically fills in the database_url? Or am I supposed to substitute mine in there?
Ooops lol
Luckily there's nothing on there yet 😉
Using the environment variables is the recommeded approach, as if you reset the database or remove / add a new one then the environment variable will be automatically updated and no code changes are required
Ok cool. so then I just want to update my config.edn file to say {:prod true :port 3000 :database_url System/getenv "DATABASE_URL"}
?
mostly. You should also use PORT environment variable for port
Ok thanks
{:prod true
:port System/getenv "PORT"
:database-url System/getenv "DATABASE_URL"}
Does this look ok or do I add parenthesis like :database-url (System/getenv "DATABASE_URL")}
Well, I've just noticed this line in the -main file, it seems that its looking for a key called :database-url https://github.com/johnbradens/kewl-app-4/blob/main/src/clj/kewl_app/core.clj#L63
so I beleive your line above should work with that - so long as the connection string is in the right form 🙂
Ok great I'll try it
{:prod true
:port (System/getenv "PORT")
:database-url (System/getenv "DATABASE_URL")}
Great thanks for your help! Ok so I just made the changes to the config.edn file, then did git add ., git commit -m "fixing things", and then git push heroku main.
How will I know if the connection string is in the right from? I guess based on whether it connects or not? Thanks again for all your help, I really appreciate it.
If it works, it was the right form, otherwise replace DATABASE_URL with JDBC_DATABASE_URL
After I compile, generally would I have to do heroku run lein run migrate
or can I just open the app and see it work?
Ok it didn't work when I opened the app just now after it recompiled. I'll try JDBC_DATABASE_URL now. Thanks!
If it complains about the port when starting the application server, then try set it in the Procfile
instead, by adding --port $PORT
to the end of the existing command
Ok I didn't see any complaints about the port so I think that part is ok
I would generally recommend running the migrations before doing git push heroku master
to deploy the application, to ensure the deployment doesnt time out running migrations (it probably wont, unless big changes are made)
Ok good to know! I will try that next time.
heroku run lein run migrate
spins up a new container that just runs the migrations, rather than the application server I beleive
Ok, so if I don't run that line, the database should still work?
The Heroku database should be running regarless of if your application is up. So you can do migrations at any time as a separate process
Deploying with git push heroku master
will build the application from source code, making an uberjar and then running the application as defined in the Procfile.
Oh ok cool
So I changed to JDBC_DATABASE_URL and just recompiled. I still see the app with "Loading messages..." and not able to login or make an account. Is this because I didn't do heroku run lein run migrate
or is there something else I have an error with?
FYI. I find the Heroku CLI very useful to see the logs as its deploying the app https://devcenter.heroku.com/articles/heroku-cli
If the errors are in the web UI, then I assume the front-end is just not being built. Heroku will just do whats defined in the uberjar task, so maybe something else needs to be done to build the web ui.
Ohh ok I see. I will have to tinker with it some more
When I run heroku run lein run migrate
I still get this error :thinking_face:
Syntax error compiling at (/tmp/form-init112362889056766708.clj:1:72). could not find a non empty configuration file to load. looked in the classpath (as a "resource") and on a file system via "conf" system property
Migrations seems to be the first thing to run when deploying the application too, so if the migrations are failing, then nothing is going to work properly. Have you tried migrations with a local postgresql database?
Would that be with heroku as well or all on my local computer? Before I deployed to Heroku, I was able to have everything working locally in my local database and using the app in localhost
The luminus template has a command (migrate) to run in the lein repl, so I was doing that before.
I'll change the database url to my local one and try lein run migrate
and see what happens.
Yeah, the luminus template probably takes a few days study to understand it well, especially if its the first web app you've created.
I found this code in the luminus-migrations.core namespace that suggests its looking for the Heroku form of database-url
, but that is an assumption and it might just use the same name
(defn- parse-url
([opts] (parse-url opts identity))
([{:keys [database-url] :as opts} transformation]
(if database-url
(-> opts
(dissoc :database-url)
(assoc-in [:db :connection-uri]
(to-jdbc-uri (transformation database-url))))
opts)))
Ok interesting. So I might try :database-url "insert heroku string with my username and password info here"
The error you get when running `heroku run lein run migrate` suggests the config.edn is not being loaded.
Did you deploy the new version of the application after making the change, i.e. git push heroku master
?
Yes every time I make a change, I do git add ., git commit, and then git push heroku main
I'll run it again now just to be sure
I am fairly sure the config.edn should use the DATABASE_URL environment variable. luminus-migrations uses migratus which takes the postgres: form of connection, so it should just work
If you added the --port $PORT
to the Procfile, I assume the :port 3000
is not needed in the config.edn file.
Ok I made those changes. I added --port $PORT at the end of the statement in my procfile, and commented it out in my env/prod/resources/config.edn file. Now my config file has just the following and I'm gonna try running it again...
{:prod true
:database-url (System/getenv "JDBC_DATABASE_URL")}
Browsing Om Next docs, I encountered this expression:
#js {:onClick
(fn [e]
(swap! app-state update-in [:count] inc))}
I can’t seem to find documentation on that reader macro. Anyone know what it does?#js
will create create a javascript object or javascript array
Ah, so it’s just an ordinary flat mutable object instead of a persistent map?
It was pretty hard to find in the docs. I couldn't find it in any of the guides.
It is in the cheatsheet though, https://cljs.info/cheatsheet/