Best way to have default user settings in Ruby on Rails? - ruby-on-rails

I'm currently working on a RoR application where users are able to register and have a list of (lets say 20) image-formats. These image-formats have their own model. The admin of the website is able to add or remove formats. The users should be able to activate certain formats or deactivate.
I was thinking of just adding the 20 formats to the database for each user, but that wouldn't be flexible if the admin chooses to delete or add one. Their should be a more maintainable way?

Your explanation isn't very detailed. Especially I'm missing the "default" settings from the question.
First thing (easy one):
The Admin can create an entry for each format he wants to allow on the website. So there should be exactly one such entry in the table
Users can select from these formats several (up to a limit?) Why do they need to specially choose them? Can't they just use everything the admin allows? What would happen to uploaded images if the admin deletes a format?
Anyway, best would be a has_and_belongs_to_many relationship between the User and ImageFormat. Or another Model (UserImageFormat) that builds this bridge if any additional data is necessary.
For the case, that the Admin removes some formats, you can handle this in several ways. Either you add an "active" flag to the format record and then check for this each time you use the model or you actually just delete this record (in this case, make sure your associations are set with :dependent => :destroy so all the records that connect users to formats get destroyed too. (Write tests to ensure this)
Maybe you can find some gems or plugins that help with that. This article may give you some more help. Maybe some of the authentication plugins can add access control. But I think your need (user can in some way influence what he can use/access) could be too special, since most gems for this kind of work will more likely address an admin centered access control.

Related

User settings and access control in rails

I have a webapp build with rails. Nothing complicated so far. Now I would like to restrict some areas for the user. I would like to implement two roles, User and Admin. Clearly the admin can do much more, like use DELETE in some of the controller methods. But there is even more. The user should be able to set some settings. For example he can set his profile to private, so only his friends can see his content. I am not sure how to build all of this with rails.
I did some research and found those two:
https://github.com/elabs/pundit
https://github.com/ledermann/rails-settings
Maybe a combination of those two would get me to the way I want the app to be?
If the app is going to be used used by real users i would go for the devise gem(https://github.com/plataformatec/devise) It allows user to create accounts, retrieve lost passwords etc. By default it allows users to edit their "profile"(rather their personal data), it should be easy to add a checkbox to toggle public/private profiles.
In conjunction with cancancan(https://github.com/CanCanCommunity/cancancan) you can assign roles to users, without having two different classes(Users and Admins for example).

what is the advantage in creating user profiles?

I noticed that many people create associated profiles to the main users of their site. What is the advantage of doing this?
Right now my app is set up to deal directly with the user for ALL of their attributes. Before I move forward I want to get some perspective on what the ideal path would be.
Thanks!
From my perspective it really depends on what kind of application this and who the users are. Some use cases where you need a profile that does not have ALL the attributes
The app administrator has control over items such as roles
One user may want to be able to look at another users profie, but that may not want to have things such as salary, employee ID, email address exposed, and should not be able to change attributes.
So really depends on the app, its users, and what yoou are trying to do

Ruby on Rails private link sharing: Google Docs Style

What would be the best way to go about giving users the ability to share a private link that enables anyone who clicks it to view a certain page/document/item that have privacy restrictions in place?
In my case:
A User creates events which are limited to certain groups of relationships in the database (namely: friends, friends of friends, etc.) I have a :before_filter in the event controller that checks the eligibility of the current logged in user to make sure that that user has permission to see the event. If they don't they get booted to the root page with an error message.
However, I want a special scenario to exist where a user can create an event with those same privacy settings and IN ADDITION, be able to share a special link with his or her friends via e-mail, facebook, etc. Those users do NOT need an account (but will need to make one in order to sign up for the event). This is important because there is also a :before_filter in the application_controller which makes sure a user is logged in.
I'm thinking there is something I could do with routing here... Right now I just have the simple /events/72 setup. Should each event have two different links: a normal one, and a "special code" version which enables them to bypass those two :before_filter?
What are people's thoughts?
I agree with David Lyod's answer (separating this concern in a different controller).
But for creating the hash I strongly recommend you salting the hash with some secret phrase.
require "digest"
Digest::SHA512.hexdigest("#{created_at}#{user_id}.mysupersonicsecretSALT")
Doing this it is not possible, without the knowlegde of the secret phrase, to calculate the hashes and test them against your system until it hits an existing one.
If you're handling sensitive data you should not be lazy.
Cheers,
Lukas
I would have a separate controller that uses a hash value to reference the event.
Something simple like the created_at + user_id hashed to create a unique reference.
You could also simply skip the check on a certain action but I would much prefer the first solution .

What's the best way to store global application settings in a Rails application?

I want to handle two kinds of global configuration settings:
Settings which can be altered by the user, like if notification mails for certain events are sent or not.
Settings which are tied to a specific product edition, like disabling a feature in a free version, which is only available in the commercial version.
What's the best way to store these settings? Database, configuration file, hardcoded in the source, ...?
For both cases database. You're going to be using the same structures for multiple people/products so it makes sense. Also it allows you to change things without restarting the server.
I've handled it this way in the past:
For settings specific to the user, I've created a UserSettings model/table, that has a one-to-one to relationship with a user. The reasoning for this is that the majority of my operations involving users do no not require these settings to be loaded, so they're only included on user loads from the database when I need them.
When I do this, I'll usually group my column names, so that I can write helpers that dynamically create based on the names. Meaning that I won't have to modify my views to incorporate new settings unless I add one with a different naming scheme.
For the settings specific to a product, well that depends on how you are doing things. And there are a couple of ways to interpret your question.
The way I read it is that you want to decide on a product level. What settings users can overriding or disabling a user's setting. And possibly define some product specific settings.
I would use a one-to-many product to setting relationship. The setting table would be something simplistic (product_id, setting_name, setting_default_value, allow_user_change)
This does a number of things. It lets you have a variable list of settings for different products (Perfect for the case where you're offering many different products instead of varying tiers of access to services). It also lets you define what settings a user can/can't change and give values for that product type. That can be changed from an administrator view without restarting the application. It's also not tied to user settings, to the point where if a user doesn't have a setting listed in the product_settings there will be no problems.
The downside is you will have multiple common settings in this table. I would move settings that every product will have a different value to a field in the product table.
You will also have to write validations to ensure that a user does not change a setting their product says they can't. You will also have to write helper methods to merge settings from the product and user sides.
class Flag < ActiveRecord::Base
# id, user_id, name, value (serialized probably)
belongs_to :user
DEFAULTS = {
"newsletter" => false
}
def self.lookup(user, flag)
# Please involve memcached here
case flag
when "ssl_enabled"
# Check if user has paid for sufficient access to SSL
return false
else
stored_flag = self.find_by_user_id_and_name(user.id, flag)
if stored_flag
return stored_flag.value
else
return DEFAULTS[flag]
end
end
end
end
class User < ActiveRecord::Base
has_many :flags
def flag(name)
return Flag.lookup(self, name)
end
end
For stuff that's product edition based, you probably can't really store things in the database, because the flag is going to be based on some piece of authorization code, rather than static data.
Here's my experience with this kind of stuff: don't override behavior.
You see, your first thought is going to be something like this:
Hmm.... There are system-wide settings that may or may not be overridden by users (or products). Hey! I know this! It's composition!
And technically, you'd be correct. So, you'll make a Settings table and put all your settings in there. And then you'll have a user_settings table, where you will override those settings if the user so decides. And it'll work fine.
Until you add a setting to one table and not the other.
Or you get a bug that Setting X can't be overridden at the user or product level and it takes more than 5 seconds to figure out exactly where that setting is set.
And then you'll realize:
Hey, I'm keeping track of all these settings in at least two different places. That seems kinda dumb.
And you'd be right.
So, yes. Go ahead and keep the settings in the DB, but save them distinctly for each user or product. Use smart default values on row creation and it'll keep things nice and simple.
For the first kind of settings, I would keep them in the User model (Users table).
The second kind of settings, would go to the database again. For example if a user had a free account, that would be somehow saved in the database. I would have some helpers in Application, for example "free?" or "commercial?". These helpers could find out if they are true or false, asking the currently connected User/Account model. You could then use these helpers across different parts in your application to decide if you show or hide certain functionality.

Allow users to remove their account

I am developing a gallery which allows users to post photos, comments, vote and do many other tasks.
Now I think that it is correct to allow users to unsubscribe and remove all their data if they want to. However it is difficult to allow such a thing because you run the risk to break your application (e.g. what should I do when a comment has many replies? what should I do with pages that have many revisions by different users?).
Photos can be easily removed, but for other data (i.e. comments, revisions...) I thought that there are three possibilities:
assign it to the admin
assign it to a user called "removed-user"
mantain the current associations (i.e. the user ID) and only rename user's data (e.g. assign a new username such as "removed-user-24" and a non-existent e-mail such as "noreply-removed-user-24#mysite.com"
What are the best practices to follow when we allow users to remove their accounts? How do you implement them (particularly in Rails)?
I've typically solved this type of problem by having an active flag on user, and simply setting active to false when the user is deleted. That way I maintain referential integrity throughout the system even if a user is "deleted". In the business layer I always validate a user is active before allowing them to perform operations. I also filter inactive users when retrieving data.
The usual thing to do is instead of deleting them from a database, add a boolean flag field and have it be true for valid users and false for invalid users. You will have to add code to filter on the flag. You should also remove all relevant data from the user that you can. The primary purpose of this flag is to keep the links intact. It is a variant of the renaming the user's data, but the flag will be easier to check.
Ideally in a system you would not want to "hard delete" data. The best way I know of and that we have implemented in past is "soft delete". Maintain a status column in all your data tables which ideally refers to the fact whether the row is active or not. Any row when created is "Active" by default; however as entries are deleted; they are made inactive.
All select queries which display data on screen filter results for only "active records". This way you get following advantages:
1. Data Recovery is possible.
2. You can have a scheduled task on database level, which can take care of hard deletes of once in a way; if really needed. (Like a SQL procedure or something)
3. You can have an admin screen to be able to decide which accounts, entries etc you'd really want to mark for deletion
4. A temperory disabling of account can also be implemented with same solution.
In prod environments where I have worked on, a hard delete is a strict No-No. Infact audits are maintained for deletes also. But if application is really small; it'd be upto user.
I would still suggest a "virtual delete" or a "soft delete" with periodic cleanup on db level; which will be faster efficient and optimized way of cleaning up.
I generally don't like to delete anything and instead opt to mark records as deleted/unpublished using states (with AASM i.e. acts as state machine).
I prefer states and events to just using flags as you can use events to update attributes and send emails etc. in one foul swoop. Then check states to decide what to do later on.
HTH.
I would recommend putting in a delete date field that contains the date/time the user unsubscribed - not only to the user record, but to all information related to that user. The app should check the field prior to displaying anything. You can then run a hard delete for all records 30 days (your choice of time) after the delete date. This will allow the information not to be shown (you will probably need to update the app in a few places), time to allow the user to re-subscribe (accidental or rethinking) and a scheduled process to delete old data. I would remove ALL information about the member and any related comments about the member or their prior published data (photos, etc.)
I am sure it changing lot since update with Data Protection and GDPR, etc.
the reason I found this page as I was looking for advice because of new Apply policy on account deletion requirements extended https://developer.apple.com/news/?id=i71db0mv
We are using Ruby on Rails right now. Your answers seem a little outdated? or not or still useful right now
I was thinking something like that
create a new table “old_user_table” with old user_id , First name, Second name, email, and booking slug.
It will allow keep all users who did previous booking. And deleted their user ID in the app. We need to keep all records for booking for audit purpose in the last 5 years in the app.
the user setup with this app, the user but never booking, then the user will not transfer to “old_user_table” cos the user never booking.
Does it make sense? something like that?

Resources