I have a shiny app that I deployed as a library. Inside my shiny app, I write a json file in real time, I want to write this file in the working directory of each user. Nevertheless, the file is written in the directory of the library.(Please refer the code below)
app.R
library(Tree)
ui <- htmlTemplate("www/Tree.html",
text_output = tableOutput("table2")
)
server <- function(input, output, session){
# This block fires each time we receive a message from JavaScript
output$table2 <- renderTable({
#Write json file
json_value = input$jsonData
write(json_value, paste0(getwd(),"/",fileName, ".json"))
})
}
# Run the application
shinyApp(ui , server)
I though that with the function getwd()I will be able to see my json file in my working directory but taht is not happening. My json file is written in the directory of the library
This directory
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Tree/
How can I change my code to be able to see my jsonfile in the RProject which the user wants to work?
A shiny app is running in your browser and, as a concequence, subject to strict safety regulations imposed by the browser. There are plenty of restrictions regarding the file system to make sure that web pages cannot freely roam your hard drive. That is why there might not be a solution with a good user experience to achieve what you want.
The safest solution would be the download button (as suggested by #HubertL).
If you want to work with the users' home directory you can get the path with file.path(Sys.getenv("HOME")) (at least on Windows it works). Now you can work with that path. Use OutputPath <- file.path(Sys.getenv("HOME"), fileName) to create the path %HOME%/fileName.
The third alternative (I can think of) is a simple textInput. Users can paste a string there that represents the path to the directory where they want the file to be stored. Check the string with dir.exists and use it if it is valid.
Related
I have developed a Shiny app for a user at a different location. This app may eventually be hosted in the cloud but for now a single user will run the application locally on their computer. What is the preferred way to share the application and also make it easy to maintain/update the scripts?
Do I need to instruct the user to install R, RStudio, all of the packages used by the application, and copy the R scripts, etc, to a local directory, and then include directions about how to run from the RStudio interface?
I'm intrigued by the runGitHub option, which seems very appealing, with one problem: It wouldn't be wise to add the file containing API tokens in the GitHub repository. Is there a way for the code to look for that specific file locally instead of in the repository?
Thank you!
You can use {dotenv} to store the secrets. For example,
create a .env in your app root folder.
In the file
username=xxxxxx
token="xxxxxx"
Make a copy of this file called .env-template.
Add .env but not .env-template to .gitignore.
Fill your real tokens in .env since this file will not be uploaded to github.
In R, use
# load secrets
library(dotenv)
load_dot_env('.env')
# to get values
Sys.getenv("username")
Sys.getenv("token")
Tell users to fill their real tokens in .env-template and rename it to .env
to use runGithub or runGist
The demo is very simple, just to get the secret token locally while running app from a remote address.
Your app code
library(shiny)
server <- function(input, output, session) {
print(Sys.getenv("token")) # just print out the token on console
}
shinyApp(div(), server)
User code will be like
library(shiny)
### first run without following 4 lines and then uncomment following and run again
### watch the difference on console
# library(dotenv)
# dotenv_file <- tempfile()
# cat('token=12345', file = dotenv_file)
# load_dot_env(dotenv_file)
###
runGist('https://gist.github.com/lz100/f54d59901a56a051770edd77e1324f21')
I made a relatively elaborate Shiny app for my job that runs great locally. However, I am trying to host the app so that users who don't have R Studio downloaded can access it. I cannot get the app to run through shinyapps.io. It seems this is mostly related to the fact that it cannot find the files that are located on Dropbox. The app is based almost entirely on loading and writing files on Dropbox. I tried to change the file paths and use rdrop2 to load the files, but it changes the formatting of some things and would be pretty complicated to reconcile as far as I can tell. I'm very much a novice programmer and the thought of having to restructure the entire app is giving me a bit of anxiety and will certainly require a fair amount of effort. Does anyone know of a more "simple" way to modify files located on Dropbox through a shiny app hosted on shinyapps.io, preferably while still able to use the "openxlsx" package? Thank you very much in advance.
One workaround I thought might work but didn't was to make the file path to the Dropbox file specific to the user because anyone using the app should have access to Dropbox:
this.data <- as.data.frame(read.xlsx(paste("C:\Users\", Sys.info()[["user"]], "\Dropbox\rest of the file path", sep = "")))
Disclaimer : I would not recommend relying on google-unsubmmitted URLs to guarantee privacy.
Modify the share link copied from DropBox replacing dl=0 by dl=1 to make the download start rather than display in DropBox UI.
You can then download.file() into a tempfile() before read.xlsx() it:
library(shiny)
library(openxlsx)
library(DT)
ui <- fluidPage(
titlePanel("XL Read from dropbox"),
mainPanel( DTOutput("dt"))
)
server <- function(input, output) {
tmpfile <- tempfile(fileext='.xlsx')
download.file(url = "https://www.dropbox.com/s/1v0l...5u803a9hg/my_file.xlsx?dl=1", destfile = tmpfile , mode="wb")
output$dt <- renderDT(read.xlsx(outfile))
}
shinyApp(ui = ui, server = server)
I'm building a shiny app that create multiple files depending on the uploade file by the user. The created files has the same names and this can make that when a user download the files end with a none relative information to his data.
How can be created an independent directory for each user in Shiny app?
I have found the next solution so far to create the directory to store the files:
directory <- paste0(format(Sys.time(),"%Y%m%d%H%M%S"),rnorm(1),
rnorm(1))
dir.create(directory)
setwd(directory)
But I have read that this may not work if I upload the app to a server. How should I do it?
This is the answer that I get in RStudio community and worked for me:
By #pieterjanvc from RStudio community:
Setting the working directory is likely not going to work like that in Shiny. I suggest you generate a folder based off the user's session token, which is generated when a user connects to a Shiny app and located in the session variable.
library(shiny)
ui <- fluidPage(
)
server <- function(input, output, session) {
dir.create(session$token)
file.create(paste0(session$token, "/userFile.txt"))
}
shinyApp(ui, server)
Once you created the directory, you can save any file in that one using again the token which is the name of the base folder for that user. You should remember to erase the folder after the task finished, or you will have a lot of folders soon.
Does anyone know i it is possible to change the default file that shiny loads?
I was hoping for a bit more flexibility than one file per directory.
It depends on your setup.
Setup 1: Run app locally from a file
If you want to run an application locally (inside an interactive R session) you can use the command
shiny::shinyAppFile("path/to/my/appFile.R")
to load an application. The app file does not have to be named app.R in that case. Note however that with this approach all relative paths (for example image paths) will be resolved relative to your working directory rather than relative to the app's directory.
Setup 2: Run app on a server
If the app shold be run via shiny-server (or shinyapps.io) things are more complicated. In this case the server will expect the app to be defined either as app.R or ui.R/server.R in order to be loaded properly. The only workaround I am aware of here is to use shinyAppFile inside app.R but this might not be very useful in most situations.
Setup 3: Define the app as an object
You can also define an app as an R object and invoke it by printing the object.
someAppObj <- shinyApp(ui = fluidPage(), server = function(...) {})
## start the app by printing it
someAppObj
As mentioned in the answer of #ismirsehregal, you can also use runApp instead of the printing method which will take care if relative paths and handle the app-environment slightly differently.
runApp(someAppObj)
Setup 1 is actually related to setup 3 since since shinyAppFile returns an app-object.
For a single file app just rename it and add
app <- shinyApp(ui = ui, server = server)
runApp(app)
to be able to source it.
Can files be uploaded to server using the shinyFiles package? I'm looking for similar functionality to the standard fileInput from the shiny package. The closest thing I could find in shinyFiles:
app.r
library(shiny)
library(shinyFiles)
server <- function(input, output, session) {
shinyFileSave(input, 'save', session=session, roots=c(wd='.')) }
ui <- bootstrapPage(shinySaveButton('save', 'Save', 'Save as...'))
shinyApp(ui=ui,server=server)
But this only allows me to browse the server files (not local) and even when I save I don't see the file created.
The short answer is no (sorry about that)... shinyFiles is simply a browser for the server file system, mainly intended for use when a shiny app is meant for local use (to avoid the overhead of file copying required in native web implementations).
The functionality of shinyFileSave is simply to let the user specify a non-existing filename at a certain location and pass that information back to the server - It's up to the server logic to handle that information in a meaningful way, by creating a file at the specified location.
You could somehow couple shinyFileSave and fileInput to upload a file and put it in a specific location, but the UI for this would probably be quite messy as it would inevitably mix shinyFiles/Bootstrap ui with native ui elements. As the local filesystem is guarded from Javascript code for security reasons this would be the only approach though as long as the server and client resides at different locations...