realm / realm-object-server

Tracking of issues related to the Realm Object Server and other general issues not related to the specific SDK's
https://realm.io
293 stars 42 forks source link

Add support for creating a user and a realm when offline #14

Open dseehof opened 8 years ago

dseehof commented 8 years ago

How would I manage to start an iOS application using the new mobile platform when the device is e.g. in Airplane Mode and no auth call to to the server is possible? Shouldn't there be a way to use the locally cached version? This is not about losing connectivity after having been authenticated when I can grab the user object and keep working, this is purely about starting the app in offline mode.

Also see this post on SO: http://stackoverflow.com/questions/39942208/synchronized-realm-airplane-mode

bmunkholm commented 8 years ago

Right now it's not possible to start the app the first time without having network connectivity. We will be adding support for that soon. For now you have to authenticate with the server the very first time the app starts.

bmunkholm commented 8 years ago

@dseehof I tried to make the feature request clear in the title - I assume this now reflects your needs?

dseehof commented 8 years ago

Much better. :-)

joshuapinter commented 7 years ago

Hey @bmunkholm, any update on being able to start in offline mode first and syncing later. I know it's a bunch of work but it's very important for real world applications to be able to use a local version and then have sync capabilities if and when an internet connection is established.

Even right now always waiting for the online database to be returned before any data is shown is not a good experience for the user. It should be able to show their local database data first and then have that update automatically as the online data gets returned.

Thanks.

jpsim commented 7 years ago

I think you misunderstand how synchronized Realms work. The only time network connectivity is required is on very first user authentication. A logged in user is persisted across app sessions, meaning that subsequent runs of the app can access the synchronized Realm immediately even when offline.

That being said, we would love to eliminate all connectivity requirements, which is why we're keeping this ticket open 😉

joshuapinter commented 7 years ago

@jpsim Yeah, I didn't realize it was persisted locally. Do you have any code examples of how to use Realm Sync but use the local database, if available?

I'm doing something like this at the moment:

Realm.Sync.User.login('http://1.2.3.4:9080', 'test@email.com', 'password', (error, user) => { 

  if (!error) {
    let synchedRealm = new Realm({
      sync: {
        user: user,
        url: 'realm://1.2.3.4:9080/~/my-realm',
      },
      schema: [Model1Schema, Model2Schema]
    });

    resolve(synchedRealm);
  }
  else {
    reject(error);
  }

});

Doing it this way the app always needs an internet connection to launch the app and connect to the database, even after they've logged on (online) for the first time.

How might I change this chunk of code to allow for local access first and sync with Realm also?

Many Thanks!

jpsim commented 7 years ago

See Realm Tasks for an example of only prompting for authentication if a current user isn't available: https://github.com/realm-demos/realm-tasks/tree/master/RealmTasks%20React

let user = Realm.Sync.User.current
if (user) {
  let synchedRealm = new Realm({
    sync: {
      user: user,
      url: 'realm://1.2.3.4:9080/~/my-realm',
    },
    schema: [Model1Schema, Model2Schema]
  });
  return synchedRealm;
}

// otherwise continue with login flow:

Realm.Sync.User.login('http://1.2.3.4:9080', 'test@email.com', 'password', (error, user) => {
//...
joshuapinter commented 7 years ago

@jpsim Awesome. I was hoping it was that straight forward. Thanks for the clarification. I'll keep watching this issue for progress on registering offline.

Cheers! 👍

joshuapinter commented 7 years ago

Hmmm, trying to get this working finally, @jpsim, and it seems that Realm.Sync.User.current returns an empty object {} even though the user has logged in before and is even online.

Looking at http://stackoverflow.com/questions/39942208/synchronized-realm-airplane-mode, it looks like @Dmitry suggests using SyncUser.all().

Can you shed some more light on this issue, please?

Many Thanks!

joshuapinter commented 7 years ago

@jpsim Also, on this Issue https://github.com/realm/realm-js/issues/857, @fealebenpae suggests using Realm.Sync.User.all to get all Users listed in the database.

Seems like a few different methods being tossed around here.

Thanks!

joshuapinter commented 7 years ago

Wait, I was able to get this working with your sample code. Even though Realm.Sync.User.current only returns an empty object {} it is still a valid user object so it can be used.

Works fantastic now. Can't wait to see the update where users will be able to authenticate for the first time offline as well.

Thanks for all your help!

agersoncgps commented 7 years ago

@jpsim, when you say "The only time network connectivity is required is on very first user authentication. A logged in user is persisted across app sessions" So if they close the app out of memory, restart the phone, or if I reload in the simulator during development would you expect it to loose its local cache and need to re-conect to network?

nirinchev commented 7 years ago

No, that cache is persisted across app restarts.

ivnsch commented 6 years ago

Have there been any updates on this?

I'm also now very confused - I opened an issue a few months ago, asking how to convert a local realm to a synced Realm which I thought would upload the local state to the remote database - but it seems I'm mistaken? What's this conversion for then?

Theoretically it should be possible to at least copy manually all the objects to the synced realm when the user logs in the first time?

Also, when the professional edition in the pricing lists (https://realm.io/pricing/) states "Offline First Support for your app" I assume it's also without this? What's the difference, then, concerning this, with the developer edition, which appears to not have this feature?

In any case, please add this feature! It's not really offline first if you can't be offline first.....

Edit: At least the manual migration seems to work, i.e. copying the objects one by one from the local realm to the synced realm (via create).

bigfish24 commented 6 years ago

@i-schuetz we have not yet added the ability to register or login the application offline. It is on our roadmap, but hasn't been a priority. This does mean that before the app can sync it must be online to login, but given that our SDKs cache the user, at that point the app can sync on or offline. I apologize for the confusion on this detail.

In the mean time, the workaround is as you suggested. You could setup your app to use a local, non-synced Realm, to store data in if the app is offline before the user can login. Once the user registers/logins you could then open the synced Realm and then just copy the data in the local Realm into the synced one.

We don't offer an API to convert a local Realm into a synced Realm, but you can follow this flow (in Swift):

let localRealm = try! Realm(configuration: localConfig)

let myLocalObjects = localRealm.objects("MyObject.self")

let syncedRealm = try! Realm(configuration: syncConfig)

try! syncedRealm.write {
    syncedRealm.add(myLocalObjects)
}
ivnsch commented 6 years ago

@bigfish24 Thanks for the clarifications and that's exactly what I did! It was a bit tedious process though, as I've a lot of objects, with dependencies among them, lists and so on. In the issue I linked there's a generic approach for this - but it has some issues (which I mentioned + an additional crash when copying specific objects, after the initial issues appeared to be fixed). Anyway I'm not interested in this approach anymore for myself, as I've managed to do it as you described.

revolter commented 6 years ago

Isn't using try! highly unsafe? Why is it used everywhere in the docs?

AndyDentFree commented 6 years ago

Agree with @i-schuetz this is a really annoying gap.

I'm porting an app from native online-only to offline-first using Realm with Xamarin Forms.

We need to allow the following workflow.

  1. User installs app
  2. User starts using app (may not have network connectivity by now).
  3. User can play with demo content, start using app completely offline.
  4. User decides to register an account and share data - at this point they login.
mikesutton commented 6 years ago

I have to confess to being really disappointed with learning about this limitation. I would have thought that you couldn't say that Realm was offline-first if you needed to be online to get that functionality!

I have pretty much the same workflow as @AndyDentFree and not being able to have immediate offline use to a database because there is no connectivity doesn't make sense.

Here's hoping you bump it up the priority list and get something sorted.

revolter commented 6 years ago

@bigfish24, Firstly, I think the best/correct way is to use ? instead of ! everywhere, because most people use this in real-life apps, not hello world apps.

Secondly, for me, it crashes with Object is already managed by another Realm. Use create instead to copy it into this Realm..

insidegui commented 6 years ago

@bigfish24 If you can, I'd suggest reviewing the priority of this issue. This is the main reason why I haven't put my project with ROS intro production yet and I'm sure a lot of people are on the same boat.

bigfish24 commented 6 years ago

@revolter my apologies. For brevity I use !, but you can expand to catch the errors (I would recommend you think through whether your app can actually really guard against a failure to open the Realm). Also, sorry about the mixup on the API as well:

let localRealm = try! Realm(configuration: localConfig)

let myLocalObjects = localRealm.objects(MyObject.self)

let syncedRealm = try! Realm(configuration: syncConfig)

try! syncedRealm.write {
    syncedRealm.create(MyObject.self, value: myLocalObjects, update: false)
}

@insidegui thanks for the feedback! We are focused on Realm Cloud right now, but we do plan to support it and we will use your input to help prioritize.

revolter commented 6 years ago

@bigfish24, I understand, but since I personally went through learning Swift and trying to integrate Realm at the same time, I found it very confusing (in the documentation), more so seeing some example code using ? instead of !. In this particular case, replacing ! with ? could be the only required change, without the need of guards, ifs or catchs. But for other code snippets that are terser this way, I would add a warning/statement explaining it.

So, I would either replace ! with ? in examples like this one, either state something like:

In real-life applications, you should use try? instead of try! or do ... catch if you want to handle a missing Realm.

intellilights commented 5 years ago

Has there been any progress on this issue? How high up on the prio list is it? We're evaluating Realm for an industrial use case where operators are not guaranteed to have internet connectivity when they're setting up the system. Thanks!

clystian commented 4 years ago

There aren't solutions with Realm 4.2 for .NET or Realm 6.0+ for java/kotlin Anyone know what happened to this problem? Any different solution to a local database and then copy to synchronized database?