Rails how to use f.select with virtual attributes - ruby-on-rails

I have a user model that contains 2 booleans in the database - admin, and readonly. Basically this allows me to have 3 levels of access (readonly, editable, and admin).
I have a screen that allows admins to edit other users permissions. Instead of having 2 checkboxes for the boolean values of admin and readonly, i created a dropdown using f.select and i created a virtual attribute called "permission".
Everything works fine when saving a user as far as permissions go, the only thing is that when you go to the edit page for a particiular user, it does not load the page with the user's actual permission in the dropdown. It just loads the first value in the dropdown as the default value.
How can i make it so this dropdown shows the users actual permission when first loading the user edit page?
Here's my virtual attribute code for my User model:
# get the permission
def permission
if self.read_only
#permission = 'readonly'
elsif self.admin
#permission = 'admin'
else
#permission = 'editable'
end
end
# Set the permission.
def permission=(value)
p "VALUE = #{value}"
if value == 'readonly'
self.read_only = true
self.admin = false
#permission = 'readonly'
elsif value == 'admin'
p "INSIDE admin"
self.read_only = false
p "before #{self.admin}"
self.admin = true
p "after #{self.admin}"
#permission = 'admin'
elsif value == 'editable'
self.read_only = false
self.admin = false
#permission = 'editable'
end
end
and here's my f.select in my form view:
<%= f.select :permission, options_for_select([['Admin', 'admin'], ['Read Only', 'readonly'], ['Editable', 'editable']], {:disabled => #permissions_disabled}) %>
I tried using collection_select, but couldn't figure out how to populate the list.

as stated in Rails f.select trying to disable a dropdown from being changed, you dont need the options_for_select. If you remove it and pass the fourth parameter a selected option, you should be set.
<%= f.select :permission, [['admin', 'Admin'], ['readonly', 'Read Only'], ['editable', 'Editable']], { selected: 'readonly' }, { disabled: #permissions_disabled } %>
but given the code above, even without the selected option, as long as f.object.permission returns the right value, you should be fine.

Try adding this to your last options hash: :selected => #user.permission
For example:
<%= f.select :permission, options_for_select([['Admin', 'admin'], ['Read Only', 'readonly'], ['Editable', 'editable']], {:disabled => #permissions_disabled, :selected => #user.permission}) %>

Related

Rails select values

I have a select option in a form:
<%= f.select :role, options_for_select(User.roles.keys.to_a, params[:role]), {}, class: 'form-control form-control-lg roleSelect' %>
These roles are defined in my model:
enum role: {user: 0, profile_user: 1}
Now in my dropdown when the user choses it shows user and profile_user as drop down option.
Is there any way to show another value to represent these in a drop down?
For example:
In the drop down I would rather show "I am a teacher" which maps to user.
In the drop down I would rather show "I am here to study" which maps to profile_user.
In your model add your narrative descriptions.
NARRATIVE_ROLES = {user: 'I am a teacher', profile_user: 'I am here to learn'}
Add a method to create the select_array
def self.roles_select
User.roles.keys.map {|role| [NARRATIVE_ROLES[role], role]}
end
Then in the select you use
options_for_select(User.roles_select, params[:role])
Or (slightly simpler)
NARRATIVE_ROLES = {'I am a teacher' => :user, 'I am here to learn' => :profile_user}
options_for_select(User::NARRATIVE_ROLES, params[:role])

Using Role Model and simple_forms to assign roles

First off, I am using Devise, Cancan, Role Model, and simple_form. Everything seems to work with permissions and whatnot. What I can't seem to do is create a form so that I can assign roles to Users.
Here is what I have so far:
<%= simple_form_for(#profile.user) do |f| %>
<%= f.input :roles_mask, as: :check_boxes, collection: User.valid_roles, :checked => [ 'member' , true] %>
<%= f.button :submit %>
This shows the check boxes properly, and the last part flags one as true. I'm not sure how to get it to flag the roles that are supposed to be flagged. I chose one at random for testing Also, if I send it to update, nothing seems to happen. I updated like I normally would limiting my params to just the roles_mask variable.
def update
if #user.update(params.require(:user).permit(:roles_mask))
flash[:notice] = "Permissions updated."
redirect_to profile_path(#user.profile_id)
else
render 'edit'
end
I have no clue what I am doing wrong. Even if I could just get them to update. Not showing the current roles isn't a huge deal.
You don't need to directly access roles_mask property, just assign roles property with the array of roles. Example:
= f.input :roles, collection: User.valid_roles, as: :check_boxes, checked: #user.roles, label_method: proc {|l| User.human_attribute_name(l) }
And don't forget to permit that form value for strong parameters:
params.require(:user).permit(roles: [])

Ruby on Rails - How to use a select box to change an attribute of the selected items?

I'll start off with a bit of context to my question. I have a group of offices which each have reviewers associated with them. A reviewer can only be associated with one office. I want to create two select boxes. One lists all of the reviewers that are associated with the office I am viewing, the other lists all of the reviewers that are available (which is basically all of the reviewers that aren't already assigned to this office).
The goal of the current reviewer's listbox is to set their office to nil when they are selected. The goal of the available reviewers listbox is to set their office to this office's id when they are selected. I'm not sure how to change only the reviewers' office_id when using a select box.
Code-wise, what I have so far is this:
office_controller.rb
def edit
#office = Group.find params[:id] if params[:id]
#current_reviewers = Reviewer.find_all_by_group_id(#office.id)
#available_reviewers = Reviewer.where('group_id <> ?',[#office.id])
end
def update
?
end
office/edit.html.erb
<% form_for(#office, :url => {:controller => :office, :action => :update, :id => #office.id}, :html => {}) do |f| %>
...
<%= select_tag 'removedReviewers', options_from_collection_for_select(#current_reviewers, "id", "display_name"), :multiple => true %>
<%= select_tag 'chosenReviewers', options_from_collection_for_select(#available_reviewers, "id", "display_name"), :multiple => true %>
...
<% end %>
Any suggestions would be greatly appreciated. Thanks!
I solved this by adding the ability to get a select_tag to get the selected objects as a collection via the [] modifier of the select_tag name. So, in this example it was:
<%= select_tag 'removedReviewers[]', options_from_collection_for_select(#current_reviewers, "id", "display_name"), :multiple => true %>
And for the controller code to handle it, I did this:
#removedReviewers = params[:removedReviewers]
if !#removedReviewers.nil?
#removedReviewers.each do |reviewer|
#reviewer = Reviewer.find(reviewer)
#reviewer.group_id = nil
#reviewer.save
end
end
And the equivalent for the chosen/available reviewers.

Using two separate fields for the same parameter in a Rails form handler?

I'm new to Rails and am fixing a Rails 2 site. I have a form that lets the user add information for the starting location (:start) EITHER with an input OR with a dropdown field. However, I have found that when I include both options, only the dropdown (which comes last) submits data, while the input is ignored. What's the right way to include both options?
MY VIEW
<% form_for #newsavedmap, :html=>{:id=>'createaMap'} do |f| %>
<%= f.error_messages %>
<p>Enter a street address, city, and state:
<%= f.text_field :start, {:id=>"startinput", :size=>50}%></p>
<p>Or, select a location from the list:
<%= f.select :start, options_for_select(#itinerary.locations), {:include_blank => true }, {:id=>"startdrop"} %>
<input type="submit" id="savethismap" value="Save Map">
<% end %>
One way to achieve this is by using virtual attributes. Since both fields map to same attribute, you are going to have to pick which one to use.
# app/models/newsavedmap.rb
class Newsavedmap < ActiveRecord::Base
...
attr_accessible :start_text, :start_select
...
def start_text=(value)
#start_text = value if value
prepare_start
end
def start_select=(value)
#start_select = value if value
prepare_start
end
# start_text will fall back to self.start if #start_text is not set
def start_text
#start_text || self.start
end
# start_select will fall back to self.start if #start_select is not set
def start_select
#start_select || self.start
end
private
def prepare_start
# Pick one of the following or use however you see fit.
self.start = start_text if start_text
self.start = start_select if start_select
end
end
Then your form needs to use the virtual attributes:
<%= f.text_field :start_text, {:id=>"startinput", :size=>50}%></p>
<p>Or, select a location from the list:
<%= f.select :start_select, options_for_select(#itinerary.locations), {:include_blank => true }, {:id=>"startdrop"} %>
Other options are:
Use text_field as the primary and update it's value with selected option if user selects an option.
Add a hidden field in your form and use JavaScript to update the hidden field's value when text_field text gets updated or select option changes

Making cookies for search options?

I need help on creating these cookies for my Search options. I've read the Rails Guide and API but still don't understand how to make cookies correctly. I have two checkboxes that filter search results. They start out as already checked but what I need it to do is save the settings in a cookie if one of them is unchecked for the next searches. Here is a picture for better understanding:
Answer:
class SearchController < ApplicationController
def index
#title = "Search"
#page_title = "Search"
# Checkboxes are already checked.
params[:online_search_checked] = true
params[:offline_search_checked] = true
restore_cookie # if user enters this page in the future we restore checkboxes state from the cookies. For the first visit checkbox value will be true.
end
def results
update_cookie # each time user submits search we need to update cookies.
restore_cookie # each time user submits search we need to show search page with correctly checked check boxes.
#title = "Search"
#page_title = "Search"
#search = Product.search do |q|
q.fulltext params[:search]
q.with(:coordinates, params[:coordinates]).near(latitude, longitude, :precision => 3) if params[:coordinates].present?
q.with(:online_search, false) if params[:online_search].nil? # search user prices that are online automatically if checkbox is checked.
q.with(:offline_search, true) if params[:offline_search].nil? # search user prices that are offline automatically if checkbox is checked.
q.paginate(:per_page => 20, :page => params[:page])
q.order_by(:purchase_date, :desc)
q.order_by(:price,:asc)
end
#products = #search.results
end
def update_cookie
update_cookie_with_param(:online_search, :online_search_checked)
update_cookie_with_param(:offline_search, :offline_search_checked)
end
def restore_cookie
restore_param_from_cookie(:online_search_checked)
restore_param_from_cookie(:offline_search_checked)
end
def update_cookie_with_param(value_param_name, checked_param_name)
checked = params[value_param_name].nil? ? "false" : "true"
cookies[checked_param_name] = { :value => checked, :expires => 2.weeks.from_now }
end
def restore_param_from_cookie(checked_param_name)
if cookies[checked_param_name]
params[checked_param_name] = (cookies[checked_param_name] == "true")
end
end
end
# On index and result page in partial
<%= form_tag results_search_index_path, :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<%= label_tag :online_search, 'Online' %>
<%= check_box_tag :online_search, 'online_search_value', params[:online_search_checked] %>
<%= label_tag :offline_search, 'Offline' %>
<%= check_box_tag :offline_search, 'offline_search_value', params[:offline_search_checked] %>
<% end %>
Cookie is a message given to a Web browser by a Web server. The
browser stores the message in a text file. The message is then sent
back to the server each time the browser requests a page from the
server.
In rails you can use cookies, cookies.permanent and cookies.signed to write cookies:
cookies - simple session cookies
cookies.permanent - create cookies
with expiration date 20 years in the future
cookies.signed - generate
signed representation of cookie to pvervent tampering of its value by
the end user.
To explain cookies usage I created two session cookies for your application: 'online_search_checked' and 'offline_search_checked'. They contain "true" or "false" values and represent whether appropriate checkbox is checked or not.
check_box_tag has following parameters: checkbox_name, checkbox_value, is_checked. We need to modify third parameter depending on the value received from the cookie. The second value may be a constant. If checkbox is checked, then params[:checkbox_name] == checkbox_value. If checkbox is unchecked, then params[:checkbox_name] == nil.
Here is the algorithm:
The first time when user hits 'search/index' he does not have
'online_search_checked' and 'offline_search_checked' cookies set.
Then you would like to show him both check boxes checked by default.
If this is not the first time then user already has cookies set and
we need to restore state of checkboxes from these cookies.
When user hits 'search/results' we update cookies with the current state of checkboxes
and restore state of checkboxes from these cookies.
Here is the code with my comments:
class SearchController < ApplicationController
def index
params[:online_search_checked] = true
params[:offline_search_checked] = true
restore_cookie # if user enters this page in the future we restore checkboxes state from the cookies. For the first visit checkbox value will be true.
end
def results
update_cookie # each time user submits search we need to update cookies
restore_cookie # each time user submits search we need to show search page with correctly checked check boxes
# Using Sunspot here.
#search = Product.search do |q|
q.fulltext params[:search]
q.with(:online_search, params[:online_search] == 1) if params[:online_search].nil?
q.with(:offline_search, params[:offline_search] == 0) if params[:offline_search].nil?
end
#products = #search.results # Sunspot rendering results.
end
def update_cookie
update_cookie_with_param(:online_search, :online_search_checked)
update_cookie_with_param(:offline_search, :offline_search_checked)
end
def restore_cookie
restore_param_from_cookie(:online_search_checked)
restore_param_from_cookie(:offline_search_checked)
end
def update_cookie_with_param(value_param_name, checked_param_name)
checked = params[value_param_name].nil? ? "false" : "true"
cookies[checked_param_name] = { :value => checked, :expires => 2.weeks.from_now }
end
def restore_param_from_cookie(checked_param_name)
if cookies[checked_param_name]
params[checked_param_name] = (cookies[checked_param_name] == "true")
end
end
end
# On index and result page in partial
<%= form_tag 'results', :method => 'get' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
<%= check_box_tag :online_search, 'online_search_value', params[:online_search_checked] %>
<%= check_box_tag :offline_search, 'offline_search_value', params[:offline_search_checked] %>
<% end %>
Hope this helps!
UPDATE
I do not quite understood what do you want to do here:
q.with(:online_search, params[:online_search] == 1) if params[:online_search].nil?
q.with(:offline_search, params[:offline_search] == 0) if params[:offline_search].nil?
In your code params[:online_search] == 1 and params[:offline_search] == 0 expressions will always be false because params[:online_search] and params[:offline_search] are nil according to if condition.

Resources