Create select based on routing, how? - ruby-on-rails

I am trying to implement navigation like in Tree Based Navigation but based on URLs defined in routes.rb (named routes, resources, ...).
Is it possible to retreive a collection of all routes defined in routes.rb?
So I can use it in a select like this:
<%= f.collection_select :url, Route.all, :url, :name %>
Tnx!

ActionController::Routing::Routes.routes
Will list available routes for the application. Will require some parsing to pull out applicable details.

Thanx to the hint of David Lyod I solved it!
Here is my code:
helper-method
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
def routes_url
routes = ActionController::Routing::Routes.routes.collect do |route|
segs = route.segments.inject("") { |str,s| str << s.to_s }
segs.chop! if segs.length > 1
segs.chomp("(.:format)")
end
routes.delete_if {|x| x.index(':id')}
return routes.compact.uniq.sort
end
end
and in my view I put:
<%= select("page", "url", options_for_select(routes_url), {:include_blank => true}) %>

Related

Create dropdown menu signup page with devise

I would like to create a dropdown menu for a list of countries in my signup page with devise. I understand that I need to create a migration
rails g migration add_countries_to_user country:string
and then I have to use create the form in my view page
<%= f.select :countries, options_for_select(%w[Alfganistan, Albania, Algeria...]) %>
I would like to know if my form correct and where can I put the countries list in because it is not right to write 200+ countries in the view page right?
Thanks.
As suggested, you can use country_select. Or, you can do it on your own as:
Create an initializer which contains list of countries (or anything in particular you want) config/initializers/countries.yml
countries:
- Afghanistan
- United States
- ...
Load it in database by creating a rake task as:
lib/tasks/load_countries.rb
namespace :db do
desc "Loads countries in database"
task :load_countries => :environment do |t|
countries_list = YAML.load("#{Rails.root}/config/initializers/countries.yml")['countries']
countries.each do |country|
Country.find_or_create_by_name(country)
end
end
end
Whenever you add any countries in yml, you can populate it by invoking this rake task: rake db:load_countries.
Maintain a model Country :
class Country < ActiveRecord::Base
validates :name, presence: true, uniqueness: { case_insensitive: true }
end
I am considering that a user belongs_to 1 country above, and a country has_many users. In your view, :
f.select :country, options_from_collection_for_select(Country.all, :id, :name)
Note: I am using association approach above, since it will make it easier to make queries against this field in future, unlike saving an actual string in user.
Use the country_select gem.
# Gemfile
gem 'country_select'
form:
country_select("user", "country")
Apart from gem and Countries read from YML.
One more option is creating a method in your helper
File : app/helpers/country_helper.rb
def get_countries
{:1=>Africa,:2=>"America"}
end
In Views you can use this way
<%= options_from_collection_for_select(get_countries, :id, :name) %>
Look up rails cast #88 revised dynamic select menus. What you need is method call grouped_collection_select in which you will map out the item you need based on how they corresponded to one another
You could do this as a helper method. eg, in your users_helper.rb you could list the selections:
def country_options
[
['Afghanistan'],
['Albania'],
...
['Zimbabwe']
]
end
Then, your selector pulls from that helper method:
<%= f.select :country, options_for_select(country_options), { prompt: 'Choose Country' } %>

Rails 4 select_tag with nested resource

I have a resource that looks like this:
resources :teams do
[...]
get 'tags/:tag', to: "teams#show", as: :tag
end
Each Team can have multiple Posts which in it's turn can have multiple Tags. In my teams show view I want to display a select_tag that lists all the tags for the Team's Posts. When the user selects a tag I want to redirect them and list all posts for that tag. I have go it to work, but not with my nested resource and the URLs that I want. My implementation currently looks like this (I use HAML):
/ View
= form_tag team_path(#team), method: 'get', class: 'tag_form' do
.input-group
= select_tag "tag", options_from_collection_for_select(#team_tags, 'id', 'name', params[:tag]), prompt: "All tags", class: 'chosen-select'
# Controller
def show
#team_tags = #team.posts.tag_counts_on(:tags)
if params[:tag] && !params[:tag].blank?
tag = Tag.find(params[:tag])
#posts = #team.posts.tagged_with(tag.name)
else
#posts = #team.posts
end
end
This works, but gives me an url that looks like this:
teams/1?utf8=✓&tag=1
What I want is:
teams/1/tags/tag-name
Is that possible to do, and how would that look?
Based on this answer, you might be able to get this to work:
= select_tag "tag",
options_from_collection_for_select(#team_tags,
'id',
'name',
params[:tag]),
{prompt: "All tags",
class: 'chosen-select'},
{onchange: "window.location.replace('/teams/' + #team.id + '/tags/' + this.value);"}
the only thing i'm not sure about is if #team.id will interpolated correctly inside :onchange, so you could also try changing the onchange line to this:
onchange: "window.location.replace('/teams/#{#team.id}/tags/' + this.value);"
Try to use, or something like this (with your fields) on the controller
tag = Tag.where("id = ? OR name = ?", params[:tag], params[:tag])
And on the select you should use the name as value, maybe with a gsub like this
tag.name.gsub(" ", "-")

how to embed raw html in active_admin formtastic

I'm trying to build a form, with formtastic, inside an active_admin model.
The problem is I need a certain script tag and other raw HTML stuff directly inside or around the form.
I'm doing it with the normal form block:
form do |f|
f.inputs :name => "User Details", :for => :user do |user_form|
user_form.input :first_name, :required => true
...
How do I embed a simple div tag right in between?
Or even a script tag?
I thought about using a render :partial, but I want to know if the above method is possible first. Thanks!
You can insert a div or javascript like this:
f.form_buffers.last << content_tag(:div, "Div content here")
f.form_buffers.last << javascript_tag("alert('hi');")
In the current ActiveAdmin the form_buffers is deprecated. Instead it's possible to do the following:
insert_tag(Arbre::HTML::Div) { content_tag(:span, "foo") }
Active admin created a DSL on top of Formtastic according to their docs
https://github.com/activeadmin/activeadmin/blob/master/docs/5-forms.md
So you can now do:
form do |f|
f.semantic_errors(*f.object.errors.keys)
import_errors = self.controller.instance_variable_get("#errors")
if import_errors.present?
ul class: 'errors' do
import_errors.each do |e|
li e
end
end
end
# ...
end

Retain Search Form Data Ruby On Rails

Trying to build a search on my homepage with simple_form (Pretty much same as formtastic). The search works fine and im getting my results but after submission I want to retain the vales with what the user submitted.
I am using a namespace for my form so how can I retain the data for the form. Here is some code which may help.
Controller
def index
#results = Property.search(params[:search])
end
View
%h1 Search Form
= simple_form_for(:search) do |f|
= f.input :location, :as => :select, :collection => Location.all.asc(:name)
= f.input :type, :collection => PropertyType.all.asc(:name)
= f.input :bedrooms, :collection => 1..10,
%p.box
= f.button :submit
-if #results
%h1 Search Results
.results
- #results.each do |property|
.result
%h1= property.title
Within the Index controller I have tried all sorts of things ie
#search = params[:search]
But each time I try something the search breaks.
What am I doing wrong ?
Hope you can advise
One approach is to do as Xavier Holt suggested, and pass in values to each input. The simpleform doco suggests:
= f.input :remember_me, :input_html => { :value => '1' }
The other approach is to have simpleform do it for you. SimpleForm will automatically populate the fields with values if you give it something like an activerecord object.
In this case, that means creating a model object:
class PropertySearchCriteria
attr_accessor :location, :type, :bedrooms
def initialize(options)
self.location = options[:location]
self.type = options[:bedrooms]
self.bedrooms = options[:bedrooms]
end
end
Then, change your controller:
def index
#property_search_criteria = PropertySearchCriteria.new(params[:search])
#results = Property.search(#property_search_criteria)
end
(you'll have to change the Property.search method as well)
Then, change your simple_form_for:
= simple_form_for(:search, #property_search_criteria) do |f|
And if you do all that, and get the stars to align just right, then simpleform will pre-populate the form fields all by itself. You may have to add some stuff to PropertySearchCriteria to get simpleform to be properly happy.
This is a lot of stuffing around just to get the values showing up, but it'll keep you sane if you need to add validations.
I'm doing something similar in the app I'm working on (I'm not using formtastic, but this should be at least very close to something that works for you). I got around it by making sure #search was a hash in the controller:
#search = params[:search] || {}
And then using #search[:key] as the :value option in all my search inputs (There's a chance you'll need to set #search.default = '' to get this working):
<%= text_field_tag :name, :value => #search[:name] %>
And that's all it took. As my app is getting more complicated and AJAXy, I've been thinking of moving the search parameters into the session information, which you might want to do now to stay ahead, but if you're just looking for a simple solution, this worked great for me.
Hope this helps!
you can try storing your parameters in session like so:
def index
#results = Property.search(params[:search])
store_search
end
def store_search
session[:search] = params[:search]
end
just be sure when you are done with the parameters that you clean them up
...
clear_search if session[:search]
def clear_search
session[:search] = nil
end

Helper method or Model or Controller?

Say I have a form_for with a select menu to assign a User on a belongs_to association:
...
form.select :user_id, #users, :prompt => "Select a User"
...
Currently I have #users in the controller as follows:
#users = User.all.map { |u| [u.full_name, u.id] }
I feel like this logic should maybe moved into a helper or even to the model.
But I am confused as to where to deal with this and how.
The general answer depends on how often you're going to use it:
helper: used often but only in views or controllers
model: used often anywhere the model can be used (other models)
controller: used rarely and only for specific actions.
However in your case, the answer is none of the above, and stop trying to reinvent the wheel. About 95% of the things people try to do with Rails are tasks that others have already done. There's a very good chance that it's either in the Rails Core or exist in either gem or plugin form.
What you're trying to do has already been done, and is built into the Rails core. It's a ActionView::Helpers::FormOpitionsHelper method called collection_select
collection_select does exactly what you want to do, it's also much more robust than a single purpose method.
It has the form of
collection_select(object, method, collection, value_method,
text_method, select_options = {}, html_options)
value_method and text_method are sent to each item in collection to get the select value and the display text for each select option. It is not required that either are column names.
Use it like this:
<% form_for #whatever do |form| %>
<%= form.collection_select :user_id, User.all, :id,
:full_name, :prompt => "Select a User" %>
<% end %>
You should put this in a model as it's logic oriented and by the way you should never do
#users = User.all.map { |u| [u.full_name, u.id] }
but
#users = User.all(:select => "full_name, id")
and if full_name is a method, something like that :
#users = User.all(:select => "last_name, first_name, id").map{|u| [User.full_name(u.first_name, u.last_name), u.id]}
That would be a model method since it has logic for the model. Helper methods should have UI level logic (whether to display a link or not) and HTML helpers (methods to generate links for example)
i think moving that to a helper is the best thing, since it just does help you with creating options for a select box, which is UI level.
But unless you would use that piece of code again, then to the model it must go! :)
The model:
def self.select_display
all(:select => "id, first_name, last_name").map { |u| [u.name, u.id] }
end
The view:
select :user_id, User.select_display
I had a similar problem and ended up using a module, in order to stay as DRY as possible (most of my models had a name and an id)
The module looked like this:
#lib/all_for_select.rb
module AllForSelect
def all_for_select(permission = :read)
#used declarative authorization for checking permissions
#replace first line with self.find(:all, if not using it
with_permissions_to(permission).find( :all,
:select =>"#{table_name}.id, #{table_name}.name",
:order => "#{table_name}.name ASC"
)
end
end
On your model, you just extend the module:
class Client < ActiveRecord::Base
extend AllForSelect
...
end
On your controller, you can call Client.all_for_select. I usually do this on a before_filter
class SalesController < ApplicationController
before_filter :fill_selects, :only => [:new, :edit, :update, :create]
...
private
def fill_selects
#clients = Client.all_for_select
end

Resources