Ruby on rails form validation for user profiles advice needed - ruby-on-rails

I have one model that holds validation rules for my edit_profiles page. On the edit profile page I'm using jquery accordion to split user edit_profile into different sections for users to edit information. Each section is a separate form.
e.g.
Basic info (form 1)
Personal Stats (form 2)
Favourite things (form 3)
About me (form 4)
My problem is successfully filling out information on one form and clicking update is unsuccessful because other validation rules that have been set are firing in because other forms are failing validation because they have not yet be filled in.
I've tried to use the validation_group gem but this seems to have no affect.
I'd like to know if there is an easy way to do this?
Can't I just bunch up validation rules for each form and put them in separate methods and only make them come into play when the update button from a matching form has been clicked?
So if the update button on form 1 is clicked the form_one_validations method would be fire for example and the unrelated validation methods won't.
I would really really appreciate an example of how to do this.
This is the action responsible for y edit_profile view:
def edit_profile
#profile = Profile.find_by_user_id(current_user.id)
end
It is based inside my profiles controller.
Kind regards

I ended up using :allow_blank
This way the fields don't have to be filled in but all other important validation rules are still enforced if they need to be.

I can propose you such approach: you can add additional fields to your model, something like "basic_info_completed" which will be set up once after user has filled all corresponding information. And make all necessary validations conditional and perform them only when such field is set to true. So before user fills all fields of profile section, they are all can be edited without validation, but after profile fields are completed, validation is turned on for that part of profile.

Related

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.

Captcha with Multipart Form Rails

I have a multipart form that I need a captcha for at the end. Essentially, a user is allowed to create/update a draft but not submit it for admin review until everything is done. There is a captcha meant for the last submission but the problem is that when I add it to the form, I can't use any of the other submit buttons because the captcha isn't filled out. Is there any way around this?
I'm using simple_captcha and Rails 3.2.
Thanks!
I haven't used simple_captcha before, but seems like you are doing #object.save_with_captcha in every case. You have multiple options to solve this, but one i came up with is:
In the controller, verify if all the fields (mandatory only i guess) are filled, and if they are, then save your object using #object.save_with_captcha, otherwise do the usual #object.save which wont trigger the captcha validation. Something like this:
def create
#object = MyObject.new(params[:my_object])
if #object.has_mandatory_fields_filled?
#object.save_with_captcha
else
#object.save
end
end
In the has_mandatory_fields_filled? method you would check that all the mandatory fields of your form are not empty/nil etc.

Handling forms in rails

I am a little confused with forms in RoR.
I have a contacts page with a corresponding method in my controller. What I am trying to do is have a form so people can leave a message. I will then be emailing that message to myself.
I have the form and everything created. However, I am a little confused on how I would actually get the data from the form once they hit the submit button. would it just be accessible through my contacts method in my controller using params[:message]?
Also, what if I had multiple forms on one page? Would I just be doing params[:message1], params[:message2], etc., in the contacts method in my controller?
Take a look at this answer for details on what exactly the params hash is. When you reference params[:message], this implies that you are POST'ing to your controller action with, say, "message[subject]=abc123", which Rails helpfully turns into a hash with a key like: params[:message]['subject'].
If you're looking to send an email, check out mail_form, which simplifies creating a non-database-backed model that get's turned into an email.
Lastly, about having multiple forms on a page: each form POST's to its action and includes all of the form elements that are children of that form in the DOM. So, only the children of that message will actually be included in the params[:message] hash. You can use fields_for to have multiple models within a single form.

Ruby on Rails - Adding a second (extremely) simple Auth layer in app

Once a user logs into their account, they are presented with a list of 'Employees'.
As of right now, when you click an employee, it takes the user to the 'show' page of that specific employee, however I want to add a 'pin-protected' aspect to that list before it renders the show page.
I want to add a simple layer of authentication that would go like this:
When a user clicks their name on a list, a text-field appears that asks for the selected employee's pin.
The user types in the pin. On submit, it compares the inputted pin against the 'pin' column for that employees' record. If it's correct it grants access to the selected employee's show page.
Is this something that is easily done in RoR? This is the first real app I have worked on, so I am having trouble wrapping my mind around a couple concepts like these.
Thanks so much!
Take a look at devise, it's most definitely your best bet for Ruby on Rails 3 authentication layer.
You're best bet if you just want to add a little functionality to your existing model class would be to add a method along the lines of:
def validate_pin(pin_to_check)
self.pin == pin_to_check
end
And then you just need to modify your employee controller so that show method checks to see if the pin has been provided (ideally via a session variable), otherwise redirect and request the pin with an additional method and route Employee#request_pin in the controller which asks the user to enter the pin, on success redirecting to the Employee#show route.
Session handling in the controller
To write the session variable, you'd need an Employee#check_pin method (as a POST route) and you'd just use the code:
session[:pin_valid] = true
Then you'd check session[:pin_valid] in your Employee#show method

changing form behavior on submit based on radio button selection

I'm using Rails 3.1.0.rc5. I want to have a form with a pair of radio buttons, enable and disable, and a field to enter an integer (expire_after_days, the number of days until ticket expiration), with a hidden field for the fixed parameter subdomain_name. I'd like to be able to use the same simple form to create, edit, or delete a record, depending on which radio button is checked.
So if enable is checked, with no record found for the subdomain_name, a record would be created on form submission.
If enable is checked, and a record is found, the existing record should be updated on form submission.
And if disable is checked, the record should be deleted on form submission.
Is this a reasonable thing to do? If so, what tips do you have for how to do it?
It's not ideal nor restful to have all 3 actions (create, update, destroy) cramped up in just one controller method, but if you wish to continue on this dirty route here's what you could do:
def my_dirty_method
if params[:enable].present?
if params[:subdomain_name].present?
# Edit subdomain
else
# Create subdomain
end
end
if params[:disable].present?
# Delete subdomain
end

Resources