Keeping Drop-downs DRY in a web app - language-agnostic

I'm writing a CMS for various forms and such, and I find I'm creating a lot of drop-downs. I don't really feel like mucking up my database with tons of random key/string value tables for simple drop-downs with 2-4 options that change very infrequently. What do you do to manage this in a responsible way?
This is language-agnostic, but I'm working in Rails, if anyone has specific advice.

We put everything into a single LookUp table in the database, with a column that mapped to an enum that described which lookup it was for (title, country, etc.).
This enabled us to add the flexibility of an "Other, please specify" option in lookup dropdowns. We made a control that encapsulated this, with a property to turn this behaviour on or off on a case-by-case basis.
If the end user picked "Other, please specify", a textbox would appear for them to enter their own value. This would be added to the lookup table, but flagged as an ad hoc item.
The table contained a flag denoting the status of each lookup value: Active, Inactive, AdHoc. Only Active ones would appear in the dropdown; AdHoc ones were those created via the "Other, please specify" option.
An admin page showed the frequency of usage of the AdHoc values, allowing the administrators of the site to promote common popular values into general usage (i.e. changing their Status flag to Active).
This may well be overkill for your app, but it worked really well for ours: the app was basically almost entirely CRUD operations on very business-specific data. We had dozens of lookups throughout the site that the customer wanted to be able to maintain themselves. This gave them total flexibility with no intervention from us.

You cold have one single dropdown table with an extra column to say what the drop down is for... limit the results with a where clause...

At my current position, we implemented a LookupCode table that contains a CodeGroup,Code, and Meaning column, as well as some others (like active). That way you have a single table that contains all of your lookup values are in a single location and you can do some quick lookups to bind to your dropdown lists.

Related

Extending a Table with Users' Individual Preferred Custom Properties

What is the most performance-efficient way to allow end-users to add custom properties to a core table used by an application.
For example, core table FRIENDS has columns ID, FIRST_NAME, LAST_NAME, and BIRTHDAY.
User 1 wants to also track additional properties FAVORITE_COLOR and LUCKY_NUMBER, but User 2 wants to also track different additional properties ZODIAC_SIGN, MARRIAGE_ANNIVERSRY_DATE, and GOLF_HANDICAP.
I have implemented two approaches for testing:
First approach: Add a new table FRIENDS_CUSTOM_PROPERTIES having an FK pointer back to FRIENDS and two columns for value pairs (KEY and VALUE such as FAVORITE_COLOR, YELLOW). This approach potentially requires many queries on FRIENDS_CUSTOM_PROPERTIES to retrieve all the properties for a given friend.
Second approach: Add extension columns right on the FRIENDS table itself of varying data types for CUSTOM_1, CUSTOM_2, ... CUSTOM_64, etc. If a user needed more custom properties than there were columns, my design would "spill over" to approach 1. This approach is more brute force but easily results in many NULL column values on many rows.
I can make both work but am unsure the best approach to determine which is better (or if there is already a clear best practice one way or another).
Thanks.
Approach number one is called entity-attribute-value as Rick James noted in the comments. It can do the job, but you sacrifice lots of useful features of SQL, like data types and constraints. See EAV FAIL for some of my writing on this.
You wrote something about running "many queries" but there's no advantage to doing that. You should plan on fetching the set of custom properties for a user in one query, and saving it to a map object in your client application.
The latter approach number two is incomplete. You would also need to store some kind of metadata so you know that for user 1, CUSTOM_1 means "Favorite Color" and CUSTOM_2 means "Lucky Number" and so on. Where do you plan to store the meaning of each column per user?
At least with the EAV design, each attribute comes with a key, so you know exactly what it means. And EAV allows for an unlimited number of properties, because each property gets a new row.
Ultimately, any design that allow for "user-defined properties" conflicts with principles of relational databases. Your columns no longer have any concept of a type. Read a book like SQL and Relation Theory to understand more about this.

Access changes table Relationships by itself

I am struggling with an issue in designing my Access database.
I am a caregiver, and part of my job is taking clients out into the community. I am attempting to build a catalog of outings to help the employees at our company come up with and store ideas for these. I want to store information for each of up to 5 types of events that clients can do at a location. That information includes the event type, when it runs and doesn't, and how much it'll cost, all of which would be user-selectable. (Separately in the same table, I want to include contact information and information that helps the user search for event locations, such as the ZIP code.) I have attempted to normalize the database by spreading event information across fields in the main table, linked to lookup tables. I am aware that Access has a limit of 32 relationships per table.
To help staff find event types, I am trying to set up a method for categorizing them. That requires setting up nested lookup tables, as shown in the first picture.
If I understand correctly, the additional "copies" of those lookup tables are aliases. When I save the setup for the relationships between those aliased lookup tables, close the Relationships window, and open it again, I find Access has changed them, as shown in the second picture. This happens whether I delete the lookup table information for each field in Datasheet View. I don't understand why it does this or how to fix it.
To answer your question:
In the object browser I see that you have only one table: t_OutingType. Therefore, the "tables" t_OutingType_2, t_OutingType_3 are just aliases; "pointers" to the same table (like a shortcut to a document). When you save the relationships and close the window, the relationship information is written to the metadata of the database. When you re-open the Relationships window Access re-builds the relationship diagram from the metadata, and it does not include the redundant aliases.
Additional advice:
Whenever you find yourself duplicating columns in a table, e.g., Event_1, Event_2, ... a little voice in your head should start shouting "Are you sure that's a good idea?" Imagine if you want to search the database for events that fall on a certain date. With the table layout described above you would need to ...
SELECT ... WHERE EventDate_1 = [theDate] OR EventDate_2 = [theDate] OR EventDate_3 = [theDate] ...
It's almost always better to split the Event information into a separate child table and maintain an association table between the child table and its parent.

Access: How to implement joining a contact to a trip?

(Table Relationships)
I'm developing a travel agency database, and I've got a table for contacts (people), a table for trips, and a junction table, people_has_trips. "Trip" refers to a table whose identity is mostly many-to-many relationships with various optional travel elements such as hotel, flight, etc. (I have doubts about this structure, but that's an issue for another question).
Anyway, I'm in the early phases of designing the form for Trips, which will almost entirely consist of subforms linking to junction tables. The problem that's given me the most difficulty so far is that of how to add a contact to a trip. I'm fairly new to access, and thus far I've been populating such tables using autofilling comboboxes, but the contacts table contains over 100,000 records, and as such some sort of search function would be prudent.
Here's what I have so far. This subform is based on the people_has_trips table, and currently is limited to showing existing records. I disabled all fields as not to allow the editing of People records, but I'm somewhat stumped as to how to handle adding more people. In my limited Access knowledge, the most logical solution to me seemed to be having a button to open a form that would allow the searching of People and perhaps the addition of new people.
Now, I have a fully realized form for entering new People (shown below), but it doesn't have any real search functionality besides Access's built-in filters. So my subform currently opens People and... does nothing else. Quite frankly, I have no idea where to go from here. Do I develop a second form for searching people, or do I build in search functionality to the primary People form, something I should probably do anyway? If so, How? And after doing either of those things, how do I then populate people_has_trips? The only answer I can think of involves the user clicking the button to open People, finding the person they want to add, and then manually entering the primary key into the subform, which surely isn't optimal.
The aforementioned People entry form
The solution, I would wager, is VBA commands. I've recently taken the time to learn some VBA, and I'm a bit more comfortable with it, but I just don't know where to begin with this problem. I'm confident that I can adapt and apply other people's VBA ideas and code, but I can't find a thread on this particular issue from which to do that! I'm guessing the reason I can't find any help for this issue is that it's so blatantly obvious that nobody has asked the question yet, or my Google skills are lacking. Either way, I'd be quite happy to facepalm in realization of the solution. Thanks any and all for their help!
You need to be focused on your core problem and as far as I understood, you want to search and add "users/contacts" to your "People on this trip" form.
Yes combo-boxes can eat up time loading 100k rows and it's not really search friendly.
In your "People in this trip" form you can:
have a text box => for search
have a combo-box => showing search result
[Search] [Add] [Clear] buttons
In theory,
search button performs a search on your TContacts table and assigns the results to the combobox. something like SELECT PersonId, FirstName, LastName From Prople WHERE firstName like #keyword OR lastNAme like #keyword ... other fields
User selects a specific result form the combo-box.
Add button then performs SQL operation adding selected user to your junction table and refresh your junction table.
something like: INSERT INTO people_has_trips (people_personId, trips_tripId) values (#selectedPersonId, #tripId); followed by requery
This is just a theory, you need to try out something and narrow it down to a specific problem. Otherwise your question might be marked as too broad.

Social Network: Delete Post in Database Without Breaking Application

Introduction
I am designing a social networking website for college students. To facilitate moderation, some students will be designated as moderators with elevated abilities to delete inappropriate posts and review flagged content.
Question
When a moderator finds a post or an event page that is inappropriate - how should the website proceed to hide or delete it without breaking the entire application?
Background
The issue becomes increasingly difficult when event pages need to be deleted but the page is linked to possibly couple thousand users. Connected users should have the ability to know an event page was deleted - so there would be no confusion.
An ability to "undo" deletion would be a huge plus. Since students will be the ones moderating, I would want the ability for superusers (i.e. website admins) to override moderator actions.
Considerations
The backend is run on MySQL with the Innodb engine.
Data integrity is important:
Foreign keys come into mind - but as it currently stands - the database schema does not employ them.
Deleted posts/pages should not come up in general search.
The ability to "undo" a delete action is preferable. Deleting an entire event page could ensue anger from the masses.
Current Solution
When content is found to violate the terms of use - add a special flag in the database (i.e. column status is changed to 1 -> indicating "inappropriate"). Content is then hidden according to this flag.
However - how does this tactic work in the whole scheme of a RELATIONAL database? Especially when it comes to search?
Case Study
Users can search and view all events that their friends are attending.
Table: Users
user_id
name
Table: Events
event_id
event_name
datetime
status (0 -> okay, 1 -> hide)
Table: Users_events
user_id
event_id
Issue with the Current Solution
How should the website filter out all the hidden or flagged content? Should there be a special covering index?
Conclusion
Designig a social networking website that has advanced moderation capabilities. How to flag content and hide potentially harmful and abusive posts/event pages while maintaining integral relationships in the database? How to optimize search to show only approved (non-flagged content?
You have the right approach.
By setting a status value and coding the application so that it behaves differently based on the value of the status, you preserve the integrity of the data and get the behavior you want.
Your searches, when you want just visible entries, just have to have "WHERE status = 0" in them so you don't get the ones that are hidden.
One small change - if you are only determining whether to hide or not, a better name for the column is hide. Then the values make sense: 0 is don't hide, and 1 is do hide.

Is there an elegant way to update model relations?

I am using Ruby on Rails, however am interested in a general solution as well. Lets say I have a model users, a model cuisines, and a relational table connecting the two allowing a user to have a list of 'favorite cuisines'. The user is presented with a list of all the cuisines and can check or uncheck them individually. For example lets say Alice starts off liking American, Indian, and Chinese food. She then unchecks Chinese and adds in Thai and hits save. Whats the best way to go about updating the relational table?
I have three solutions, but since this operation seems so common I was hoping for a more elegant solution. If there isn't, what is the standard way to do this?
keep a set of added and a set of removed, and make sure they have no overlap
drop all of the users favorite foods and insert the selected ones
make ajax calls to update each individual add and remove
use the association_ids approach. Instead of looking for a list cuisines and then assigning them to the user, just get a list of their ids and assign it to user.cuisine_ids. Saving the record will generate the association records for you. Since you're using checkboxes, be wary of the scenario where a user unchecks everything and then saves. What usually happens is no change is saved keeping the old selected cuisines selected. This can be easily fixed by adding a nil hidden value with the same name as the checkboxes.