How to add a extra field in todo application created using Play framework using Scala? I am using anorm DB... I am getting an error named "not found: value Task" in Application.scala at line 24. I have tried it out, please point out my mistake. Thanks in advance!
task.scala:
package models
import anorm._
import anorm.SqlParser._
import play.api.db._
import play.api.Play.current
case class Task(id: Long, label: String, name: String)
object Task {
val task = {
get[Long]("id") ~
get[String]("label") ~
get[String]("name") map {
case label~name => Task(id, name)
case id~label => Task(id, label)
}
}
def all(): List[Task] = DB.withConnection { implicit c =>
SQL("select * from task").as(task *)
}
def create(task: Task): Unit= {
DB.withConnection { implicit c =>
SQL("insert into task (label,name) values ({label},{name})").on(
'label -> label,
'name -> name
).executeUpdate()
}
}
def delete(id: Long) {
DB.withConnection { implicit c =>
SQL("delete from task where id = {id}").on(
'id -> id
).executeUpdate()
}
}
}
application.scala (controller class):
package controllers
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.data.Form
import play.api.data.Forms.{tuple,nonEmptyText}
import play.api.mvc.{Action, Controller}
import anorm.NotAssigned
import models.Task
object Application extends Controller {
def index = Action {
Redirect(routes.Application.tasks)
}
val taskForm = Form(
tuple(
"label" -> nonEmptyText,
"name" -> nonEmptyText
)
)
def tasks = Action {
Ok(views.html.index(Task.all(), taskForm))
}
def showTask= Action {
Ok(views.html.test(Task.all(), taskForm))
}
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
{
case (label, name) => {
Task.create(Task(NotAssigned, label, name))
Redirect(routes.Application.showTask)
}
}
)
}
def deleteTask(id: Long) = Action {
Task.delete(id)
Redirect(routes.Application.showTask)
}
}
Index (view file):
#(tasks: List[Task], taskForm: Form[(String, String)])
#import helper._
<h2>Add a new task</h2>
#form(routes.Application.newTask) {
#inputText(taskForm("label"))
#inputText(taskForm("name"))
<input type="submit" value="Create">
}
test.html (view file 2):
#(tasks: List[Task], taskForm: Form[(String,String)])
#import helper._
#main("Todo list") {
<h1>#tasks.size task(s)</h1>
<ul>
#tasks.map { task =>
<li>
<b>#task.label</b>
<b>#task.name</b>
#form(routes.Application.deleteTask(task.id)) {
<input type="submit" value="Delete">
}
</li>
}
</ul>
}
Try to use :
(apply) and (unapply)
methods properly for form element.
(Task.apply)(Task.unapply)
import models.Task._ imports all the methods on the companion object models.Task into the current scope, not the Task class and object themselves. So the current code would allow you to just call all and it would refer to Task.all
Change the import to import models.Task to instead get Task into the scope in your Application object and you will be able to use the task methods like you are trying to.
Related
I would like to cache a response of a controller while considering the language. With this page here on stackoverflow I was able to make almost everything right but I have one problem when I use the cache and click on a link on the webpage to change the language : it doesn't work directly : the language changes only after I refresh the page and it works perfectly when I try without the cache. The cacheHelper :
package controllers
import play.api.cache.Cached
import play.api.Configuration
import play.api.mvc._
import javax.inject.{ Inject, Singleton }
#Singleton
class CacheHelper #Inject() (val cached: Cached)(implicit configuration: Configuration) {
def apply(label: String, duration: Int)(action: EssentialAction) = {
cached({ r: RequestHeader => label + "." + getLanguage(r) }, duration) { action }
}
def getLanguage(request: RequestHeader): String = {
request.cookies.get("PLAY_LANG").map(_.value).getOrElse("fr")
}
}
the controller :
package controllers
import javax.inject._
import play.api.i18n._
import scala.concurrent.ExecutionContext
import play.api.mvc.{Action, Controller, EssentialAction, RequestHeader}
#Singleton
class ActuController #Inject() (val cacheHelper: CacheHelper, val messagesApi: MessagesApi)(implicit ec: ExecutionContext) extends Controller with I18nSupport {
def index = cacheHelper("homePage", 60) {
Action { implicit req =>
cacheHelper.getLanguage(req) match {
case "fr" => Ok("Bonjour le monde")
case "ru" => Ok("привет")
case _ => Ok("hello")
}
}
}
}
I have tried to set directly a "PLAY_LANG" cookie instead of using #withLang directly but it doesn't work either. Any ideas ? Thanks.
the "language changer" :
package controllers
import play.api.mvc._
import play.api.i18n.{ MessagesApi, Messages, Lang }
import javax.inject.{ Inject, Singleton }
import play.api.cache.Cached
#Singleton
class Application #Inject() (val messagesApi: MessagesApi) extends Controller {
def selectLang(lang: String) = Action { implicit request =>
request.headers.get(REFERER).map { referer =>
Redirect(referer).withLang(Lang(lang))
}.getOrElse {
Redirect(routes.Application.index).withLang(Lang(lang))
}
}
}
Hello Stackoverflow community!
I have i18n working in my Play 2.4 application, so that's a good start.
What I want to do now is to override the implicit Lang sent to a template. For example, if the IP address is located in Sweden, I want to set the implicit Lang to Swedish regardless of what preferred language is set in the browser. How to do this?
This is my code:
My Application.scala controller:
package controllers
import javax.inject.Inject
import play.api.i18n.{I18nSupport, Lang, MessagesApi}
import play.api.mvc._
class Application #Inject() (val messagesApi: MessagesApi) extends Controller with I18nSupport {
def index = Action { implicit request =>
if (isIpAddressLocatedInSweden) {
implicit val langFromIp = Lang.apply("sv")
Logger.info("Language set to Swedish")
}
Ok(views.html.index())
}
private def isIpAddressLocatedInSweden: Boolean = {
[...]
}
}
My index.scala.html view:
#()(implicit messages: Messages, lang: Lang)
#main("Page Title") {
<span>#lang.toString()</span>
<h1>#Messages("home.title")</h1>
}
Unfortunately, the result is:
The <span> element contains the preferred browser language: "Lang(en,)"
The <h1> element contains the value I've written in messages.en
Thanks for any help!
I've done a little bit different:
I forced the result to the language in the query string.
It's a good form to keep the work and look for better approach later:
NOTE: I USED THE "MessagesApi" to make it happen.
package controllers
import play.api._
import play.api.mvc._
import play.api.i18n.I18nSupport
import play.api.i18n.Messages.Implicits._
import play.api.i18n.MessagesApi
import javax.inject.Inject
import play.api.i18n.Lang
import play.api.i18n._
class Application# Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {
def index = Action {
implicit request =>
request.getQueryString("lang") match {
case Some(lang) => messagesApi.setLang(Ok(views.html.index()(messagesApi, Lang(lang))), Lang(lang))
case None => messagesApi.setLang(Ok(views.html.index()(messagesApi, Lang("en"))), Lang("en"))
}
}
}
conf/application.conf:
play.i18n.langs=["en","pt","fr"]
#()(implicit message: MessagesApi ,l: Lang)
<header>
<li>
<!-- change the language -->
<a href="./?lang=en">
<img src="#routes.Assets.versioned(" images/BR.png ")" />
</a>
</li>
<li>
<a href="./?lang=en">
<img src="#routes.Assets.versioned(" images/US.gif ")" />
</a>
</li>
<h1>#message("intro")</h1>
</header>
<p>#Html(message("description"))</p>
<p>#Html(message("description.education"))</p>
Conflicting implicits prevent exactly overriding Messages on Play 2.4 but I believe you can get what you were roughly looking for with the code below.
This is my code:
My conf/Application.conf:
# The application languages
# ~~~~~
play.i18n.langs = [ "en", "sv" ]
My conf/messages.sv
home.title=Svedish
My Application.scala controller:
package controllers
import javax.inject.Inject
import play.api.i18n.{I18nSupport, Lang, MessagesApi}
import play.api.mvc._
class IPMessages(lang: Lang, messages: MessagesApi) extends play.api.i18n.Messages(lang, messages){}
class Application #Inject() (val messagesApi: MessagesApi) extends Controller with I18nSupport {
def index = Action { implicit request =>
val langFromIp = if (isIpAddressLocatedInSweden) {
new Lang("sv")
} else {
request.acceptLanguages.head
}
implicit val ipMessages: IPMessages = new IPMessages(langFromIp, messagesApi)
Ok(views.html.index())
}
private def isIpAddressLocatedInSweden: Boolean = true
}
My index.scala.html view:
#()(implicit messages: IPMessages)
#main("Page Title") {
<span>#messages.toString()</span>
<h1>#messages("home.title")</h1>
}
This is the cleanest way I got it to work:
Code of my Application.scala controller:
class Application #Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {
def index = Action { implicit request =>
val lang = if (isIpAddressLocatedInSweden) {
Lang.apply("sv")
} else {
Lang.preferred(request.acceptLanguages)
}
Ok(views.html.index()).withLang(lang)
}
private def isIpAddressLocatedInSweden: Boolean = {
[...]
}
}
The code of the index.scala.html view is unchanged.
i have created a simply login submit form using playframework and scala without connecting any database.
my application.scala which is my controller i have written the code
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.mvc.Request
import views.html._
case class Userdata(email:String,password:String)
object Application extends Controller {
case class Userdata(email:String,password:String)
val userForm = Form(
mapping(
"email" -> text,
"password" -> text
)(Userdata.apply)(Userdata.unapply)
)
def usercheck = Action{ implicit request=>
userForm.bindFromRequest.fold(
formWithErrors => BadRequest(views.html.login(formWithErrors)),
Userdata => { Ok(views.html.index("congrates"))}
)}
def index() = Action {
implicit request=>
Ok(views.html.login(userForm))
}
and my view template is login.scala.html..
#(form: Form[(String,String)])
#import helper._
#form(routes.Application.usercheck){
<form class=frmuuser>
<input type=text placeholder=email id='emailid'>
<input type=password placeholder=password id='pwd'>
<input type=submit value=login id='enter'>
</form>
}
but it is not working and giving me error
type mismatch; found : play.api.data.Form[controllers.Application.Userdata] required: play.api.data.Form[(String, String)]
in this line of contoller
formWithErrors => BadRequest(views.html.login(formWithErrors)),
what is soultion for my problem??
Few points to note:
Put your case class Userdata outside the Application controller. That is move it inside controller package.
Also you can add #import at the beginning of your template, to import any arbitrary package or class.
Try this.
Application.scala: only one Userdata case class definition ( you had two of these classes defined )
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.mvc.Request
import views.html._
case class Userdata(email:String, password:String)
object Application extends Controller {
val userForm = Form(
mapping(
"email" -> text,
"password" -> text
)(Userdata.apply)(Userdata.unapply)
)
def usercheck = Action{ implicit request=>
userForm.bindFromRequest.fold(
formWithErrors => BadRequest(views.html.login(formWithErrors)),
Userdata => { Ok(views.html.index("congrates"))}
)}
def index() = Action {
implicit request=>
Ok(views.html.login(userForm))
}
login.scala.html: use Userdata instead of (String, String)
#(form: Form[Userdata])
#import helper._
#form(routes.Application.usercheck){
<form class=frmuuser>
<input type=text placeholder=email id='emailid'>
<input type=password placeholder=password id='pwd'>
<input type=submit value=login id='enter'>
</form>
}
Pretty new to scala and play and I have been assigned a task to test someone else app,which is running fine btw.Please check if my tests are right and what is the error.
This is employeeEntry.scala file in models
package models
import models.database.Employee
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick._
import play.api.Play.current
case class EmployeeEntry(eid :Int, ename: String, eadd: String, emob: String)
object Employee {
val DBemp = TableQuery[Employee]
def savedat(value: EmployeeEntry):Long = {
DB.withSession { implicit session =>
DBemp+=EmployeeEntry(eid=value.eid,ename=value.ename,eadd=value.eadd,emob=value.emob)
}}
/*val query = for (c <- Employee) yield c.ename
val result = DB.withSession {
implicit session =>
query.list // <- takes session implicitly
}*/
//val query = for (c <- Employee) yield c.ename
def getPersonList: List[EmployeeEntry] = DB.withSession { implicit session => DBemp.list }
def Update: Int = DB.withSession { implicit session =>
(DBemp filter (_.eid === 1) map (s => (s.ename,s.eadd))) update ("test","khair")}
def delet :Int =DB.withSession {
implicit session => (DBemp filter (_.eid === 1)).delete
}
}
And this is file Employee.scala in models/database
package models.database
import models._
import models.EmployeeEntry
import play.api.db.slick.Config.driver.simple._
import scala.slick.lifted._
class Employee(tag:Tag) extends Table[EmployeeEntry](tag,"employee")
{
//val a = "hello"
def eid = column[Int]("eid", O.PrimaryKey)
def ename = column[String]("name", O.DBType("VARCHAR(50)"))
def emob = column[String]("emob",O.DBType("VARCHAR(10)"))
def eadd =column[String]("eadd",O.DBType("VARCHAR(100)"))
def * = (eid, ename, emob, eadd) <> (EmployeeEntry.tupled, EmployeeEntry.unapply)
}
Finally this is my test I am running,which is failing :
import play.api.db.slick.Config.driver.simple._
import play.api.db.slick._
import play.api.Play.current
import org.scalatest.FunSpec
import org.scalatest.matchers.ShouldMatchers
import models.database.Employee
import scala.slick.lifted._
import models._
import models.EmployeeEntry
//import scala.slick.driver.H2Driver.simple._
class databasetest extends FunSpec with ShouldMatchers{
describe("this is to check database layer"){
it("can save a row"){
val a = EmployeeEntry(1006,"udit","schd","90909090")
Employee.savedat(a) should be (1)
}
it("getpersonlist"){
Employee.getPersonList.size should be (1)
}
}
}
The test is failing and error is
java.lang.RuntimeException: There is no started application
at scala.sys.package$.error(package.scala:27)
at play.api.Play$$anonfun$current$1.apply(Play.scala:71)
at play.api.Play$$anonfun$current$1.apply(Play.scala:71)
at scala.Option.getOrElse(Option.scala:120)
at play.api.Play$.current(Play.scala:71)
at models.Employee$.getPersonList(EmployeeEntry.scala:27)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply$mcV$sp(databasetest.scala:39)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply(databasetest.scala:39)
at databasetest$$anonfun$1$$anonfun$apply$mcV$sp$2.apply(databasetest.scala:39)
at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
By default play provides spec2 testing framework.so no need to add scalatest framework for unit testing.For database access layer testing required a connection with database so start a fake application.(this is not running code, just an idea to write unit test)
for more detail take a look play doc : https://www.playframework.com/documentation/2.3.x/ScalaFunctionalTestingWithSpecs2
import org.specs2.mutable.Specification
import models.database.Employee
import models._
import models.EmployeeEntry
import play.api.test.FakeApplication
import play.api.test.Helpers.running
import play.api.Play.current
class databasetest extends Specification {
"database layer" should {
"save a row" in {
running(FakeApplication()) {
val a = EmployeeEntry(1006,"udit","schd","90909090")
Employee.savedat(a) must be equalTo (1)
}
}
"get list" in {
running(FakeApplication()) {
Employee.getPersonList.size must be equalTo (1)
}
}
}
i have attached my codes
Application (controller)
package controllers
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import models.Task
import java.io._
object Application extends Controller {
val taskForm = Form(
tuple(
"id" -> number,
"label" -> nonEmptyText(minLength = 4),
"add" -> nonEmptyText
)
)
def index = Action {
Redirect(routes.Application.tasks)
}
def tasks = Action {
Ok(views.html.index(Task.all(),taskForm))
}
def showTask= Action {
Ok(views.html.test(Task.all(), taskForm))
}
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
{
case(id,label,add) => {
Task.create(id,label,add)
Redirect(routes.Application.showTask)
}
}
)
}
def deleteTask(id: Int) = Action {
Task.delete(id)
Redirect(routes.Application.showTask)
}
}
Task(model)
package models
import anorm._
import anorm.SqlParser._
import play.api.db._
import play.api.Play.current
case class Task(id: Int, label: String,add:String)
object Task {
val task = {
get[Int]("id") ~
get[String]("label") ~
get[String]("add") map {
case id~label~add => Task(id, label,add)
}
}
def all(): List[Task] = DB.withConnection { implicit c =>
SQL("select * from task").as(task *)
}
def create(id:Int , label: String, add:String) {
DB.withConnection { implicit c =>
SQL("insert into task (id,label,add) values ({id},{label},{add})").on(
'id -> id ,
'label -> label ,
'add -> add
).executeUpdate()
}
}
def delete(id:Int) {
DB.withConnection { implicit c =>
SQL("delete from task where id = {id}").on(
'id -> id
).executeUpdate()
}
}
}
I have no idea where to declare the writer function .please help me with the syntax also, I need to write the form elements into a text file .. Thankx in advance
Assuming that you want to append the text whenever a new task is added (i.e. newTask is invoked by Play).
You can define a helper function in object Application and use this helper method in your newTask method.
object Application extends Controller {
//...
import java.io.FileWriter
val filePath = """ path to file """
def writingToFile(str: String) = {
val fw = new FileWriter(filePath, true)
try {
fw.write(str)
} finally {
fw.close()
}
}
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
{
case(id,label,add) => {
/* Call the helper function to append to the file */
writingToFile(s"id : $id, label : $label, add : $add \n")
Task.create(id,label,add)
Redirect(routes.Application.showTask)
}
}
)
}
//..
}
Likewise when other methods are invoked you may append to the file in similar fashion.
Hope it helps :)