Ruby on Rails. How to show record only once? - ruby-on-rails

I want to know how to show a record only exactly after it was created. So i want to show it only once.
Just see. I have model called Claim. User creates new Claim (user is anonymous). I want to show this Claim only ofter user creates it and never again. How can I do it?
I think that I can use flash hash, but i think it is not enough secure to create symbols from user data.

You could have a viewed attribute on your model that you set to true in the show action. If viewed is true then skip rendering the view.
unless thingy.viewed
thingy.viewed = true
thingy.save
render like normal...
end

Related

Sharing the variables between the actions in the controller in Rails

I am working on a module where I have to take the consent of the user to save the set of records.
those set of records are created in an action, which has to be made available in another action of the same controller, the records are being saved by the user consent.
now I can send these set of records to UI, from UI to again controller, if the user continues to save, if not cancel.
Problem is there will be thousands of records, which is painful to carry between UI and controller so My plan is to make the set of records available to the action which is being called by the continue button
the code
def create
#valid_members = generate_member_upload_results(params[:member_upload_user][:members_list])
end
in this action #valid_members is going to have the set of records. after this action executes in UI we will ask user whether the records are to be saved if no then cancels if yes then the following action will takes palce
def create_member
count = 0
unless #valid_members.blank?
#valid_members.each do |m|
count = count + 1
m.save(:validate => false)
end
end
redirect_to :back , notice:'#{count} members records created'
end
I want my #valid member should the same object which I used in create def.
I'm not entirely sure this is feasible with the flow you're suggesting. This sounds like something that could be resolved with a multi-step form but you would need to pass the data across or temporarily store it, which is seemingly what you're trying to avoid.
Alternatively, can you create a Rails endpoint that services the first step via javascript directly from the frontend? That can return the data without the user leaving the page, they can then confirm they are happy and submit the page once with approval.

Recording activities of every controller in rails

I have created a log model and a method in every controller to keep record of action performed in every controller. that method populate logs modle. But i don't know how keep record of user creation, deletion and update using this function.
The method that i have created is:-
def keep_record(msg)
#log = Log.new
#log.user_id = current_user.id
#log.description = msg
#log.save
end
How can i use this method to keep record of creating, editing and removing user in devise gem.
Can anyone suggest me how to modify Registration_controller to keep record of creating, deleting and updating user.
I'm not sure what you mean by "track the activities", but it sounds like you want to track when a user changes those attributes. I would suggest looking into ActionCable, which the user will make a connection with, and basically subscribe to a channel, and you can record what they are doing.
Here is a good place to start:
Actioncable connected users list

Rails 5 access profile data anywhere in session without querying database each time

I've a user profile (with name, logo, about_me) which is created after user creation(using Devise). Profile table uses user_id as Primary key.
Now I want that whenever the user creates/updates a post, while filling in form some details are taken from profile, so profile data or #profile be available in post form as I cannot expose my model in form.
To set post.myname attribute in create and #update I'm doing this:
#myprofile = Profile.find_by_user_id(current_user)
write_attribute(:myname, #myprofile.name)
I read from various sources but what's the best solution of the 4 given and if anyone can back with easy code as I do not want to do something extensive? Thanks in advance.
1)Form Hidden fields - Like get the profile data as above in hash in #edit and then pass through form and access fields in #update but that way we will pass each field separately. Can one #myprofile be passed?
2)Session - I feel if profile data is stored in a session and someone updates profile then updated data won't be available in that session.So not sure if it is plausible.
3)Caching - easy way to do that?
4)polymorphic profile---tried it but I didnot get relevant example. I was stuck with what to put as profileable id and type and how to use them in the code.
If your Profile and User models have a one-to-one relationship with each other, the simplest solution is to remove the Profile model altogether and move its fields into the User model.
Devise already queries the database to obtain the current_user object. So, your example would like this:
write_attribute(:myname, current_user.name)
Which wouldn't hit the database (after Devise has retrieved the current_user object).
If you're forced to keep the Profile model, in looking at your four scenarios ...
You could use a session variable. Something like:
session[:profile_name] ||= #myprofile.name
This would go in a controller action.
The trick here is that you will want to redefine the each relevant session variable if the profile gets updated. And because you don't have access to the session in the model, you'd be best to perform that action in the controller. So, not pretty, but it could work.
You could also use low-level caching, and save the profile relationship on the user. In general, you could have a method like this in your user model:
def profile_cached
Rails.cache.fetch(['Profile', profile.id]) do
profile
end
end
Here, too, you will have to know when to expire the cache. The benefit of this approach is that you can put this code in the model, which means you can hook its expiration in a callback.
Read more about this in Caching with Rails.
I would avoid hidden fields and I'm not sure how a polymorphic relationship would solve you not hitting the database. So, #2 and #3 are options, but if you can combine the two models into one, that should simplify it.

Rails - User Pressing 'Back' after object creation, Creating Duplicates

I'm having a problem where when a user fills out my evaluation form, click "Create", then click the browser's back button, make some edits, and click "Create" again, it's creating duplicate Evaluations.
What is the best way to prevent something like this happening.
Only ONE evaluation should exist for each survey_criterion on creation. I don't want the user to lose any data they enter after hitting the back button, filling out the form with new stuff, and clicking "Create" again.
UPDATE
routes.rb
resources :survey_criteria do
resources :groups do
resources :evaluations
end
end
survey_criterion.rb
has_many :evaluations
evaluation.rb
belongs_to :survey_criterion
belongs_to :group
There are more complicated associations, but the answer I'm looking for is more, "how does one handle it when users press the 'Back' button, modify the form, then click Create again".
I want it to update the one that was automatically created I think in this instance, and not throw an error to the user. I know I could add a validation that would error out, but I want this to be invisible to the user I think.
Thoughts?
The simplest solution, would be to change the create action, which should work like this pseudocode:
def create
# ...
if evaluation_exists?
update_evaluation(params[:evaluation])
else
create_evaluation(params[:evaluation])
end
# ...
end
As for Your question "how does one handle it when users press the 'Back' button, modify the form, then click Create again", then I use some random token (a short string) placed as a hidden field in the form.
When the create-request comes, I check whether this token is already stored in the session. If it is not, then I create the object, and add that token to the list of used ones. If the token is already present in the session, I know that user has just resubmitted the form, and I can act accordingly. Usually I ask him whether another object should be created. In the session I store usually not more that 3-5 tokens.
It looks like this (yes, that's just an illustration):
def create
token = params[:token]
session[:tokens] ||= []
if session[:tokens].include? token
render_the_form_again( "You have already created the object. Want another?" )
else
create_the_object
session[:tokens] << token
end
# ...
end
In your Evaluation model, add this line :
validates_uniqueness_of :survey_criterion_id
This is assuming that SurveyCriterion holds the foreign key that associates with your Evaluation.
You can also do 2 things :
Prevent the browser cache.
Disable the Create button with :disable_with => "Processing" option.
It is discussed here too: https://stackoverflow.com/a/12112007/553371
A less elegant way but more generic way to do this is to use history.pushState. On the page after create:
$(function(){
if(history.pushState){
window.onpopstate = function(event){
if(window.history.state && window.history.state.previousStep){
window.location = window.history.state.previousStep;
}
}
window.history.replaceState({ previousStep: '#{edit_resource_url(resource)}'}, document.title, window.location);
window.history.pushState({}, document.title, window.location);
}
})
This example uses HTML5's History API. A similar thing can be done with fallback using the history.js project

How to store where a new user was referred? Using Rails + Devise

I have a rails app that uses devise. I'm curious to know, is it possible in the User table to somehow track where a new user came from, the HTTP referrer?
I'd like to know which came from Facebook, Twitter, LinkedIn, Google+ in order to track a viral loop.
Any ideas? Seen anyone do this? Possible? Where should this live in the rails app? Still very new. Thanks
It could be done like this. May require some tweaking and fixing but You'll get an idea
Make before filter for Application controller, you will call it for any action
def landing_filter
if from_other_site(request.referrer) and !session[:referer].blank?
session[:referer] = request.referrer #you don't want to delete first entrance
end
end
from_other_site should be the method which will check domain name in referrer url, if it match your then return false, otherwise true
in devise/registration/new.erb.html view add in form hidden field
<%= f.hidden_field :referrer, session[:referrer] %>
and don't forget to add migration with new database field for user
Save referer somewhere and after creating a user copy information to user table. Using session to save referer works but permanent cookies are better. Cookies can persist the information even when user closes browser and comes again in the next day.
# so basically in ApplicationContreller using before_filter
def referer_before_filter
if cookies[:referer].blank?
cookies.permanent[:referer] = request.env["HTTP_REFERER"] || 'none'
end
end
# and in signup action somewhere else saving that information
#user.referer = cookies[:referer] # or maybe to some other table
Instead of modifying every action you can also use rails sweepers/observers to handle automatic saving every time an object is created.
A good gem to automatically save referer and other needed information is
https://github.com/holli/referer_tracking . You can choose do you want to save information manually or use sweepers to do saving automatically.

Resources