I have an array of strings, called #theModels, in a routine implemented as part of a Sinatra server. These models are options for the user to select, and are obtained by the back end (the idea being, as new models are added, then the front end code should not change).
I'm using haml to render html.
How can I enumerate each element in the list of #theModels such that each element is a checkbox? And how can I obtain which checkboxes the user has selected?
I see that just putting
= #theModels
will give me the list of strings contained in #theModels, but without spacing or the like, and certainly not in checkboxes. I've found this question that appears to be similar, but my haml-fu isn't good enough to convert that into what I need.
UPDATE:
These are options associated with a file upload, such that now the code looks like:
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
Problem is, that puts a file upload button on each option, instead of at the end. I only want one submit button in the end; should I have two forms that both report their results when the 'Upload' button is pressed?
UPDATE2:
After a moment's thought, the above can be modified to:
Thanks!
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
And that appears to do what I want.
I think you should send the content as an hash instead.
This will give you the opportunity to set initial values in the form.
The hash #params will give you the result.
E.g. {"oranges"=>"1"}
#app.haml
%form{:method => 'post', :action => "/"}
- #models.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type => :submit, :value => "Save"}
#app.rb
require 'sinatra'
require 'haml'
get '/' do
#models = {"oranges" => true, "bananas" => false}
haml :app
end
post '/' do
#params.inspect
end
The link you provided linked to a rails solution where you have a function returning the proper html.
You can define this function yourself:
Input: key, value
Output: %input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
def check_box(key, value)
...
end
and call it in haml with
=check_box(key,value)
Related
Im glad you answered my question about my dev issue, I'll try to be more self-explanatory this time.
I have a main app.rb where I use several endpoints redirecting to my Sinatra Haml views.My project is about a Software Portfolio, so I have this class: Software, and Category, which relationship is: one software has one category, and a category has many softwares. In the form where you create a new Software entry, I put a dropdown list where you can choose between 3 different categories: Desktop, Web and App.
Until there, everything is going well. The thing is, when the Software list shows up, I want to put a dropdown list to filter by created categories (I already have the "add category" form with its Class) and I can't figure out how to add the filter within a Filter button in the software list form. Can you guys help me please? Of course I know how to put the button there, but I want to show only the software entries where the selected category matches. Here's the list form.
%select{:name => "category"}
%option Desktop
%option Web
%option Device
%input{:type => "submit", :value => "Filter", :class => "btn"}
%ul.list
- #sware.each do |software|
%div{:class =>"list-group"}
%a{:href =>"/software/edit/#{software.id}", :class =>"btn btn-lg btn-primary"}
= software.title
%a.pull-right(href="/software/delete/#{software.id}" class="btn btn-lg btn-danger") Delete
Thanks a lot in advance!
You're calling the index method like this:
post '/all' do
index(:category)
end
You're passing an argument to the index call, but the index method doesn't take any arguments.
Please include the full error with your question.
index action can be DRY'ed:
def index
category = case
when params[:Web] then :Web
when params[:Desktop] then :Desktop
when params[:Device] then :Device
end
#sware = Software.title.where(categorization: { Software.categorization => category })
end
"It just doesn't work" is not a good place to start investigation of the problem. More debug information is required.
Beside the point that #max pleaner made, you're not actually calling the right object in params. It should be params[:category] and you should be able to rewrite that much simpler:
get '/all' do
halt(401,'Not Authorized, please login to continue') unless session[:admin]
#sware = Software.all
haml :sware
end
post '/:category' do
#sware = Software.title.where(categorization: {Software.categorization => params[:category]}
haml :index # assuming index.haml is where you want to go
end
Then, assuming your file is properly indented, your Haml file should work as well:
%select{:name => 'category'}
%option Desktop
%option Web
%option Device
%input{:type => 'submit', :value => 'Filter', :class => 'btn'}
%ul.list
- #sware.each do |software|
%div{:class =>'list-group'}
%a{:href =>"/software/edit/#{software.id}", :class =>'btn btn-lg btn-primary'}
= software.title
%a.pull-right{:href=>"/software/delete/#{software.id}" :class=>'btn btn-lg btn-danger'} Delete
Of course, the more information you can provide, the better the problem can be understood.
Hi I'm having trouble downloading multiple files with axlsx. The problem is I'm sending an array of Id's to the controller and asking it to download the report using the render command. It raises an AbstractController::DoubleRenderError. I was thinking of overriding the error but realized it's a bad idea, I don't know what else to do... Any suggestions? Thanks.
My controller code looks like this:
def download_report
params[:user_id].each do |user_id|
#report = Report.find_by(:user_id => user_id)
render :xlsx => "download_report", :filename => "#{#report.user.last_name}.xlsx"
end
end
My axlsx template:
wb = xlsx_package.workbook
wb.add_worksheet(name: "Reports") do |sheet|
wb.styles do |s|
# template code
end
end
It is the built in expectation of Rails that you would call render once per request. And, the browser is going to expect one response per request. So, you are going to have to do something else!
You can use render_to_string, and combine the results into a zip file, serving that. See the bottom of this response.
Or, you could create a single spreadsheet and have each user's report show up on their own worksheet.
Or, on the client side, you could use javascript to request each spreadsheet and download each one separately.
The zip one would be something like this code, which uses render_to_string, rubyzip, and send_data:
def download_report
compressed_filestream = Zip::ZipOutputStream.write_buffer do |zos|
params[:user_id].each do |user_id|
#report = Report.find_by(:user_id => user_id)
content = render_to_string :xlsx => "download_report", :filename => "#{#report.user.last_name}.xlsx"
zos.put_next_entry("user_#{user_id}.xlsx")
zos.print content
end
end
compressed_filestream.rewind
send_data compressed_filestream.read, :filename => 'download_report.zip', :type => "application/zip"
end
Axlsx requires rubyzip, so you should have it already. And you probably want to lookup each user and use their name for the spreadsheet, unless you have it otherwise.
So this is ruby right, and while I do have a solution already, which I'll show below, its not tight. Feels like I'm using ahem "C++ iterators", if you will. Too many lines of code. Not like ruby.
Anyway, I'm wondering if there is classier way to do this:
b = Watir::Browser.new
b.goto "javascriptinjectedtablevalues.com" #not real website url:)
# desired urls in list are immediately located within <span> tags with a "class" of
#"name" plus a custom html attribute attribute of "data-bind" = "name: $data". that's it
# unless I wanted to use child-selectors which I'm not very good at
allrows = b.spans(:class => "name").each_with_index.map do |x, i|
[0, x.attribute_value("data-bind")]
end
real_row_ids = allrows.select{|i, databind| databind == "name: $data" }.map(&:first) #now I have all correct span ids
spans = real_row_ids.map {|id| b.spans(:class => "name")[id] }
Now that's a little messy in my opinion. But it leaves artifacts so I can debug and go back and stuff.
I could use this command to just grab a just the spans
spans = b.spans(:class => "name").map do |span|
[span, span.attribute_value("data-bind")]
end.select {|span, databind| databind == "name: $data"}.map(&:first)
but that still feels messy having no artifacts to show for it to use for later when trying to isolate other html tags nearby the span.
I'm hoping there is something like this pseudo code for watir:
b.spans(:class => "name").with_custom_attributes(:key => "data-bind", :value => "name: $data")
that's what I'd really like to do. superman-patching this custom method onto Watir within a rails initializer would be the optimal solution second to it already existing within Watir!
Watir already supports using data attributes for locators. You simply need to replace the dashes with underscores.
For example:
b.spans(:class => 'name', :data_bind => "name: $data")
Would match elements like:
<span class="name" data-bind="name: $data">
Similarly, you can use a regex when matching the data attribute:
b.spans(:class => 'name', :data_bind => /name/)
I'm trying to delete several files based on a list but I'm having problems getting the params from the chekcbox's
This is my list.haml:
%form(method="post" action="/selection" enctype="multipart/form-data")
- #files.each do |file|
%br
%input{:type => "checkbox", :name => "checkbox[]", :value => "#{file}" }
=file
%br
%input(type='submit' value="Delete Selected Files")
Now, for now I was just trying to see what I get in params, so I can later deal with how to delete this list of files.
params.inspect
"Gives me" ≃> {"checkbox"=>["yet_another_file.txt", "file1", "file2"]}
But I can't figure out how do I put this into an Array so I can do something like
var.each do |c|
puts c
end
I tried var = params[:checkbox] but var is empty, does anyone now how can I do this?
Thanks
You should use var = params["checkbox"], since the params key is not a symbol, but a string.
Clarification: The creator of the post should be able to decide when the truncation should happen.
I implemented a Wordpress like [---MORE---] functionality in my blog with following helper function:
# application_helper.rb
def more_split(content)
split = content.split("[---MORE---]")
split.first
end
def remove_more_tag(content)
content.sub(“[---MORE---]", '')
end
In the index view the post body will display everything up to (but without) the [---MORE---] tag.
# index.html.erb
<%= raw more_split(post.rendered_body) %>
And in the show view everything from the post body will be displayed except the [---MORE---] tag.
# show.html.erb
<%=raw remove_more_tag(#post.rendered_body) %>
This solution currently works for me without any problems.
Since I am still a beginner in programming I am constantly wondering if there is a more elegant way to accomplish this.
How would you do this?
Thanks for your time.
This is the updated version:
# index.html.erb
<%=raw truncate(post.rendered_body,
:length => 0,
:separator => '[---MORE---]',
:omission => link_to( "Continued...",post)) %>
...and in the show view:
# show.html.erb
<%=raw (#post.rendered_body).gsub("[---MORE---]", '') %>
I would use just simply truncate, it has all of the options you need.
truncate("And they found that many people were sleeping better.", :length => 25, :omission => '... (continued)')
# => "And they f... (continued)"
Update
After sawing the comments, and digging a bit the documentation it seems that the :separator does the work.
From the doc:
Pass a :separator to truncate text at a natural break.
For referenece see the docs
truncate(post.rendered_body, :separator => '[---MORE---]')
On the show page you have to use gsub
You could use a helper function on the index page that only grabs the first X characters in your string. So, it would look more like:
<%= raw summarize(post.rendered_body, 250) %>
to get the first 250 characters in your post. So, then you don't have to deal w/ splitting on the [---MORE---] string. And, on the show page for your post, you won't need to do anything at all... just render the post.body.
Here's an example summarize helper (that you would put in application_helper.rb):
def summarize(body, length)
return simple_format(truncate(body.gsub(/<\/?.*?>/, ""), :length => length)).gsub(/<\/?.*?>/, "")
end
I tried and found this one is the best and easiest
def summarize(body, length)
return simple_format = body[0..length]+'...'
end
s = summarize("to get the first n characters in your post. So, then you don't have to deal w/ splitting on the [---MORE---] post.body.",20)
ruby-1.9.2-p290 :017 > s
=> "to get the first n ..."