I want to change the role field in devise sign up dynamically - ruby-on-rails

In my user model i add
ROLES = Role.all.collect(&:name)
In my view part of sign up in
<% if can? :manage, #users %>
<p><%= f.label :role %>: <%= f.collection_select :role, User::ROLES, :to_s, :humanize, {:include_blank => true} %></p>
<% end %>
The problem is ROLES = Role.all.collect(&:name) is not updated when i add and edit . For example i add new role user then i have to restart the server to see the changes in the role inside the signup field. How can i update the changes in role without restart the server?

Well, the simple solution
<% if can? :manage, #users %>
<p><%= f.label :role %>: <%= f.collection_select :role, Role.all.map(&:name), :to_s, :humanize, {:include_blank => true} %></p>
<% end %>
You can also place this in a helper, or let the controller handle the retrieving of the roles (e.g. set a instance variable #roles).
So in short: do not use a constant :)

Use a class method instead of a constant:
def self.roles
Role.all.collect(&:name)
end
Of course, this is provided for free if user has many roles.

Related

Rails: show only specific objects inside a form select field

I have a form which I'm creating tokens for users. First I find all the users #users = User.order('name ASC') inside a controller. Then inside the create token form I have a select field from which I'm trying to show only the users that don't have a token:
<% #users.each do |user| %>
<% if user.token.blank? %>
<%= f.input :user_id, collection: user, label: "Associate with", value_method: :id, :include_blank => "Select a user" %>
<% end %>
<% end %>
But for some reason I'm getting this error:
undefined method `to_a' for #<User:0x00007f95a54086b0>
Did you mean? to_s
Any idea how I can fix this?
UPDATE.
Just to clarify stuff. You get this error because you pass one single user as a collection to the input. And expecting collection it will try to convert whatever you passed to array. But it won't be able to properly convert a single user to array. So you should have passed a collection of users instead. Like this:
<%= f.input :user_id, collection: #users, label: "Associate with", value_method: :id, :include_blank => "Select a user" %>
Of course, doing this you will need to have the users without tokens already assigned to your #users variable.
Or as I understand your problem, I can offer an alternative:
So assuming users without a token have token column set to nil you can do something like this:
<%= f.select :users, options_for_select(#users.where(token: nil).pluck(:name, :id)), include_blank: true %>
This will eliminate your need to iterate #users explicitly and to create an input for each of them i.e. the code above should replace this completely
<% #users.each do |user| %>
<% if user.token.blank? %>
<%= f.input :user_id, collection: user, label: "Associate with", value_method: :id, :include_blank => "Select a user" %>
<% end %>
<% end %>
Of course feel free to adjust that select helper as you need.
If you do not need #users with tokens anywhere in the current controller action or form, you should consider assigning #users = User.where(token: nil) right in your controller action.
#users should already contain the users who do not have a token to do so:
<%= f.input :user_id, collection: #users, label: "Associate with", value_method: :id, :include_blank => "Select a user" %>

Rails, use a form field to set something on the user registration (devise)

I would really like to add a form field "invite_code" to the user sign up form, but I don't know how to add the invite_code to the controller so that the application knows how to look for it?
The form in the sign up on the template would read:
<% form_for User.new do |f| %>
<span>Email:</span> <% f.email %><br>
<span>Name:</span> <% f.name %><br>
<span>Invite Code:</span> <% f.invite_code %><br>
<% end %>
The "invite_code" isn't part of the database or anything, but in the user registration model, I want to put a:
before_save :invite_promo
def invite_promo
if #invite_code.present? && #invite_code == "special_person"
self.special_key = true
end
end
Is there an easy way to look for form fields in the template using the model or controller?
So sorry...I'm new to Rails. Thank you so much in advance!
You need to define a virtual attribute invite_code in User model:
attr_accessor :invite_code
Your form should look as follows:
<%= form_for User.new do |f| %>
<span>Email:</span> <%= f.email_field :email %><br>
<span>Name:</span> <%= f.text_field :name %><br>
<span>Invite Code:</span> <%= f.text_field :invite_code %><br>
<% end %>
if you don't want to create a field inside your table, you can use hidden field in view like, <%= hidden_field_tag :invite_code, 'code' %>

How to pass simple_form hidden_field paramer to create action

I am having trouble passing a parameter defined in a hidden_field of a simple_form to a create action. In our app, a User has many bets through memberships. Membership columns include bet_id, user_id, accepted:boolean, and against:boolean. The against column of Membership indicates whether the user is betting against or betting with the bet. In the view for a particular bet, a user who does not have a membership can choose "Agree" or "Against", which will create a new membership with the appropriate accepted:boolean. Here are the forms found the the bet show page.
<%= simple_form_for([#bet, #bet.memberships.build]) do |f| %>
<%= f.hidden_field :against, against: false %>
<%= f.button :submit, "Agree!" %>
<% end %>
<%= simple_form_for([#bet, #bet.memberships.build]) do |f| %>
<%= f.hidden_field :against, against: true %>
<%= f.button :submit, "Against!" %>
<% end %>
Here is the attempted create action
def create
#membership = current_user.memberships.build(bet_id: params[:bet_id], against: params[:against], accepted: :false)
redirect_to :back
end
This currently just leaves the accepted value as nil. Any help would really be appreciated! Thanks
Try using this:
<%= f.hidden_field :against, value: false %>

Ruby on Rails access whole params hash

I have an application that deals with user rotas - and I'm currently adding the ability for admin approvals. If the user updates their own rota the params hash looks something like:
Parameters: {id:1, role_id: 1, team_id:1, rota: [startDate: 01/01/2014, endDate:02/02/2014]}
and these are submitted using a form with:
<%= form_for [#team,#role,#rota] do |f| %>
form code
<% end %>
We need to access the attributes outside the rota: object but currently can't find a way to as:
params.require requires you to pass an object in.
My team members have decided to add hidden fields to submit the attributes within the rota object but that seems redundant seeing as they are quite clearly there, we just can't find a way to access them, and ideas?
I was talking about something like
def user_rota_params
params.require(:user)
.permit(:role_id, :team_id, :rota => [:startDate, :endDate])
end
Then, for your nested attributes you could use fields_for.
Your form, thus, should look something this (omitting labels and keeping it basic):
<%= form_for #user do |f| %>
<%= f.text_field :role_id %>
<%= f.text_field :team_id %>
<%= f.fields_for :rota do |ff| %>
<%= ff.date_field :startDate %>
<%= ff.date_field :endDate %>
<% end %>
<% end %>

ActionMailer delivery when following parameters met

Forgive me for asking what i believe is quite an in depth challenge (well for me at the moment anyway)
I have a small app that allows users to check in, check out and hopefully receive emails when a book has been checked back in by registering their interest via a remind me button
So far I have setup actionmailer (basic setup)
class ReminderMailer < ActionMailer::Base
default from: "email address"
def remind_email(book)
#book = book
#url = "http://localhost:3000"
mail(:to => #book.user.email, :subject => "Book Reminder")
end
I have all the config in place to send the emails as I am already doing that through devise.
I have also created the mailer templates. It is the logic I am stuck with.
So when a User checks a book out i pass this back to the model
<%= form_for #book do |f| %>
<%= f.label :checked_out, "Check Book Out?" %>
<%= f.check_box :checked_out, {}, true %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :checked_out, :value => true %>
<%= f.submit 'Checkout' %>
<% end %>
Check In
<%= form_for #book do |f| %>
<%= f.label :checked_out, "Check Book Back In" %>
<%= f.check_box :checked_out, {checked: false}, false %>
<%= f.hidden_field :user_id, :value => nil %>
<%= f.hidden_field :checked_out, :value => false %>
<%= f.submit 'Check In' %>
<% end %>
Register Interest
<%= form_for #book do |f| %>
<%= f.label :remind_me, "let Me know when book back in" %>
<%= f.check_box :remind_me, {checked: false}, false %>
<%= f.hidden_field :remind_me, :value => current_user.id %>
<%= f.submit 'Remind Me' %>
<% end %>
So my thinking is that when you register your interest your user id gets placed into the remind_me column, and what i want to achieve is that when the checked_out field is false and book.user_id is back to nil I would like the email to send the the user whos user_id is in the remind_me column
Am i thinking about this in the correct way?
if anyone can help it would be appreciated so that i can learn from this and then keep practicing it until I understand what is going on
There are 2 ways to answer:
The first one, don't use a form to check in a book and just call a method. For example: You replace your form with a link which call a new method in your controller:
<%= link_to "check in", check_in_book_path(#book.id) %>
In your books_controller you call a model method which check in the book:
def check_in
#book = Book.find params[:id]
#book.check_in!
redirect_to book_path(#book)
end
In your book model:
def check_in!
self.user = nil
self.checked_out = false
if self.save
RemindMailer.remind_mail(self).deliver
end
end
Don't forget to add the route for your new controller method.
The second way, if you keep your form, is shorter but more complicated. You need to add a callback to your model which will verify if the data changed. For example, in you book model:
after_save :send_mail_if_check_in
def send_mail_if_check_in
if !self.checked_out && self.changes[:user_id] && self.user.nil?
RemindMailer.remind_mail(self).deliver
end
end
I prefer the first solution because it seems to be a state machine which is more maintenable.
I hope this help

Resources