I'm trying to allow users to vote a record up/down with Ajax. I'm using the vote_fu plugin for the voting functionality, and everything works fine without Ajax. I'm now trying to figure out the best way to implement the asynchronous functionality with unobtrusive javascript.
What I'm doing now is having two buttons, "Up" and "Down", such that when you click either one, a request is made to votes_controller and the create or update action, depending on if the user had already submitted a vote on that record before. The params submitted would be the record_id as well as the value of the vote.
With Ajax, how should I handle the case where a user enters a page to vote without having voted on the record before? Specifically, the links would go to the votes#create in the beginning, but after that first submission, the links should switch to votes#update.
Is there a standard way to take care of this? I was thinking about just adding an extra check in the "create" method such that it would act like "update" if it found a record for the user_id, voteable_id pair, but this seemed kind of clumsy and not fully RESTful.
Thanks,
Eric
There are several techniques/patterns commonly used:
1) When your erb creates the page, you can supply a parameter to the JS script that is a part of the page. The parameter will be the "voting_url" it will be either votes/new or votes/123 depending on whether a create or update operation should be used.
2) You could use a "procedure call" as opposed to a rest call. The procedure/action would be "change_vote" -- with a param of 'up' which would be either true or false. The action would create the vote record if needed, or would otherwise modify it.
3) As part of the creation process of the main record, you could always create the vote_record. That way, the voting operations would always be updates since the vote_record will always already exist.
Added
Re: comment of when is it generally "acceptable" to move away from a rest call?
Rest is a design philosophy. It solves a lot of problems but doesn't fit all situations. I'd think that your original question would be ok but ultimately it is up to you and whomever reviews your architecture. Since it is possible to "bend" your app into a rest api for this function, some might tell you to do so--to thereby gain the benefit of not violating Restfulness.
Re: your example in your comment about friend relationships:
Since it makes sense to "create a friend relationship" it'd be better, other things being equal, to express the api as a rest "friendship object/create" call. It was exactly for your friending example that rest was created. -- The old style alternative is that each api developer had to figure out a large set of procedure names.
Rest provides a more consistent, standard way of creating the names.
Note that a "change_vote" procedure would be best defined as part of the votes object: either votes/change_vote or something similar. I believe that there is a "Rails way" for urls for rest procedures that don't fit the standard rest verbs.
Another idea would be yo change the url (through a helper probably) depending if the record is a new one.
Something like:
link_to_remote "Up", :url => voting_path(#vote)
module VotesHelper
def voting_path(vote)
if vote.new_record?
new_voting_path
else
edit_voting_path(vote)
end
end
end
Related
I have a Rails app and I would like to save the state of my divs if a user is logged in.
Exemple: someone is logged in and clicks on a div to hide it. I would like that to be stored somewhere so if he opens the page again, this div will still be hidden.
I don't want to use local storage, because I want the state to be saved if I go on a mobile or another computer/browser too. It needs to be the same everywhere, depending on the user.
I was thinking about storing each state of each div as boolean in my user model, but this idea does not sound clean at all and I don't think I'll be able to sleep at night if I do this
Any idea?
I think React/Redux would handle that easily (maybe not and it's just local too?) but at the moment I am stuck with Rails..
Thanks a lot!
React/Redux will not save you since nothing magical happens there except for some convenient binding. Behind the curtains they use the same "browser features".
I'm afraid you need to find the best trade-off for you. I'll post some ideas:
Stick to localStorage
Probably not need to say much here since you investigated this.
Bound to Chrome
Since Chrome 25, they gave access to storage.sync and you can develop your system around this. Always try to retrieve data, if there is any and then remember to persist new data and sync it. Maybe other browsers support this, but the downside is you'll have to have the code for those as well.
Experiment with webRTC
You can transfer data between two browsers using webRTC. While I don't have many experience with this, I can't recommend it, but it's definetly an approach you'd like to consider.
Maybe check this project: https://github.com/cjb/serverless-webrtc
Create your own storage
Pick up a storage (I think even firebase/dynamodb will work) and build a system to save user preferences. If you have Auth0, you can keep some logic in there and since they are offering SSO, it will be fairly easy to check for those customizations.
Remember, since you don't want to use localStorage, you'll need to keep sessions and save this preference under a user_id or something.
In my opinion, there is no best solution for this but only what you want to trade in order to support this. If you don't mind keeping the whole business logic, I don't see why creating a storage for this will make it too slow. Measure the load and optimize along the way.
It sounds like this is a user preferences type of configuration. As such, you can probably just store the settings as single field in your User modal. For that you could use either a serializable hash or json type.
So assuming you have a app/models/user.rb
Add an run migration
rails g migration add_view_options_to_users view_options:text
rake db:migrate
Add this to your model
class User < ActiveRecord::Base
serialize :view_options, Hash
end
Then in your users controller you can post to your update action so you'll want to add a field to permitted_params
private
def permitted_params
params.require(:user).permit(:view_options, #other options etc.)
end
From here you'll need to write some javascript to post view_options to users/update or custom route if you prefer. But basically each field's value will be saved inside a controller action so something like:
def update
#user = User.find(params[:id])
opts = #user.view_options || {}
user.view_options = opts.merge(params[:view_options])
if #user.save
render json: { status: true, user_id: #user.id }
else
render json: { status: false, errors: #user.errors.full_messages }
end
end
I don't understand how does ECMAScript works. Check on MSDN and other forum it didnt tell us which version or values equal to javascrpt.
if (!Request.Browser.JavaScript)
//Do Something.
However, I was given a warning of obsolute and recommend me to use ECMAScript instead.
System.Web.HttpBrowserCapabilities myBrowserCaps = Request.Browser;
if (((System.Web.Configuration.HttpCapabilitiesBase)myBrowserCaps).EcmaScriptVersion.Major < 1)
//Does not have Javascript. Do something.
However, I tried both on/off my javascript. Somehow the function was not fired. I suspect certain values belong to javascript. However, I cant find anything related to value == javascript.
I understand I could a Then perform a redirect using meta tag. But I would like all these code to perform at the server.
First of all, see Should I bother to develop for JavaScript disabled? / How important is graceful degradation of JavaScript? .
Then, client-side Javascript only exists in the client and if it's off, no client-side logic will fire to check anything explicitly. So you cannot know it until the client sends at least one reply from your page (be it a GET/POST query or an XMLHTTPRequest) - i.e. only after the second request from that very user, generated by the very page you sent them, which may never occur if they just lurk around, even if you make every link on your page a form reply - they may use URLs from an external source. A CodeProject article linked from Check if javascript is disabled? is one example of such approach.
For this reason (and to avoid effort duplication to make both script and noscript versions - the practice that saw some use in the past), the best practice appears to have become making pages and frameworks JavaScript-agnostic and just warning the user with <noscript> that the page may not be fully functional if it's relevant.
E.g. Sharepoint does just that - with JS disabled, a warning appears on top while on the page, there are e.g. no scrollbars and editing is disabled completely. Which leads to conclusion that ASP.NET controls (which SP makes heavy use of) weren't designed to be functional beyond basic display with JS disabled in the first place.
I'm pretty new to this world so I need some clarifications on it. Maybe I could be wrong on the subject. So, feel free to correct me.
I'm studying how Marionette and Backbone work together. Oh yeah. Marionette gives us extension to Backbone. Really nice stuff.
The thing that is not obvious to me is when to use the routing mechanism provided by Backbone and when to use publisher/subscriber pattern by Marionette.
Is there any rule of thumb?
Here, Where to use event aggregator in backbone marionette?, a similar discussion but there is no advice on how using that or the other.
My take on the route management is explained in the free preview to my book on Marionette (http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf)
Basically, my opinion (others don't necessarily share it) is that Backbone's routing should be used to configure the application state when the user "enters" the application via a URL. In other words, it will parse parameters, and call proper controller actions.
But once that initial state is setup, routing code should no longer be triggered, even as the user navigates through the application.
Here's an example:
The user enters arrives on the "contacts/2/edit". Backbone routing code will extract the 2 argument and call the edit controller action with that id parameter (which fetches that contact, displays the proper views, etc.). In other words, the initial application state is being configured.
The user clicks on the "show all contacts" link leading to the "contacts" URL. Here, I believe this modification should be handled through Marionette events (i.e. indicating the user wants to see all contacts). After all, we know what the user wants to do, and which URL fragment should be displayed. In other words, there is no reason for the routing code to get involved.
Note that this is my opinion, and other developers simply pass trigger: true when the user clicks a link. But as I explain in the book extract linked above, this tends to lead developers to create "stateless applications in javascript" (e.g. passing lots of parameters in the URL, even though they should be stored in the application's state). Ater all there is a reason that by default, Backbone's navigate method has trigger: false.
Derick Bailey (Marionette's creator) also discussed the issue here: http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/
Event aggregator is more useful for notifying things. (think small bits of feedback)
Message from server (updated record)
Let other models know things have changed
Lock everything down while saving until saved
Single Moment in time things
Router is for things where you want the state to be save-able (think separate page in a MPA)
Model Edit Page
Model View Page
Something that will stay until another event or activity changes it
If you are not sure if something is an event or a page, then think about it and ask that separate question.
*I was wondering if i could do all these in javascript, as opposed to having rails helpers
In my application, there are several types of "if-else" UI cases. This is a fairly common scenario, and i wonder if anyone has a tidy way to do these?
EG 1) There might be several types of links with the same behavior: "upvote", etc.
If it is the user's own article, i do not want it to be passed to the server, but pop up a dialog box
EG 2) There might be a several links called "follow", "become a fan", etc
If the user already have done the given action before, it should be a text "followed" instead of a link.
Normally you'd use helpers for this. You write helpers called, based on your examples, upvote_button (which might take a user as a parameter) or follow_button (where this one might take true/false for already-following/not-following.
If you can be more specific as to what you need, I can probably be more specific in my answer.
I'm getting in to a situation where I have several interacting widgets (on a web UI), all of whom can be in multiple different states, and whose behavior depends on others the others. I'm running in to situations where, for example, a set of data gets sorted twice, or the data gets displayed before it's sorted, rather than the other way around. It's a little bit of a wack-a-mole problem, where I think I've simplified things and gotten it working, only to find out I've broken things somewhere else.
I have functions that do things like:
widgetAFunction
load data into widget B
tell widget B to sort the data
tell widget B to display the data
My love of code reuse makes me want to do something like write a loadData function in widget A that goes something like this:
widgetBLoadDataFunction
update data
sort the data
refresh the view
So that all widgetA has to do is call one function on widgetB. But then there are cases where I just want to sort the data, without updating the data, so I write:
widgetBSortFunction
sort the data
refresh the view
And then maybe I want a filter function
widgetBFilterFunction
filter the data
refresh the view
And maybe I want to be update the data but not sort it, so I have
widgetBNoSortLoadDataFunction
update data
refresh the view
It doesn't seem that complex, but I wind up with these really long, very brittle chains of function calls, or a bunch of very similar calls. As Martin Fowler would say, the code is getting a little smelly.
So, what other alternatives do I have? I did something on a recent project where I did a state machine kind of thing, where I registered a bunch of functions with a set of conditions, or states which would trigger their execution. That worked somewhat well, and I'm thinking that approach might be good to use again.
Does anyone know what I'm talking about here, and even better, can anyone point me toward some patterns that will help me get my head around this better?
What you need is a finite state machine implementation. Basically every finite state machine needs:
Events that the program responds to
States where the program waits between events
Transitions between states in response to events
Actions taken during transitions
Variables that hold values needed by actions between events
A good article from IBM teachs you a way of implementing it by means of Javascript.
Edit: Here is a FSM builder, so you don't have to build your own.
Fernando already mentioned FSMs, and gave good info and links. :)
In addition, I'll add that your classes should already incorporate enough state so that you're not worried about sorting twice, etc. I.e., widgetB.sort() should check if it's been sorted since last update and just return if so. There's practically no downside to doing this, and it can improve performance (and also guard consistency).