Linking to an API - html

I am trying to access a weather API that shows the icon of current weather.
My current code is:
response = HTTParty.get('http://api.openweathermap.org/data/2.5/weather?id=5911606&appid=734d8f2204043326b51df724c5c917f4', format: :json)
body = JSON.parse(response.body)["weather"][0]
#icon=body["icon"]
In html i am using the icon like:
<%= link_to image_tag('http://openweathermap.org/img/w/' + #icon +".png", :size => '130x130', :style => 'margin-top:45px;'), root_path%>
Its working fine when i first starts the server, but as I clicked any other link its gives me the following error:
nil is not a valid asset source
Does anybody know how to fix this?

it seems you are getting an empty #icon object. you can check for for empty icon object with #icon.blank? like following
<%= link_to image_tag('http://openweathermap.org/img/w/' + #icon +".png", :size => '130x130', :style => 'margin-top:45px;'), root_path unless #icon.blank? %>
if you can also think if having a helper method to display a default icon if the #icon is retuning a blank value
That means when you open any other links, I presume it calls a different actions where your code for #icon is not getting called and it is nil.
if you want #icon to be available for all the actions. You have to probably do it in a before action where you call the method populating #icon

Related

Submitting an empty text field as an empty string, not null, in a multipart form

This is happening in my Rails app, but I'm not sure whether this is an issue with Rails or if I'm misunderstanding how multipart forms are supposed to work.
Here's (something like) my form:
<%= form_for #user do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
User#name has a presence validation. If I visit users/1/edit, empty out the value of the 'name' text field, and click submit, nothing gets updated because the presence validation fails. So far, so good.
But now I've added an avatar attribute to my User (using the Paperclip gem for file storage), so I update the form accordingly:
<%= form_for #user do |f| %>
<%= f.text_field :name %>
<%= f.file_field :avatar %>
<%= f.submit %>
<% end %>
Now, if I go to edit the user and submit a blank value for name, the validation doesn't fail. User#name keeps it previous value, but the update still appears to be successful (i.e. I don't get an error message about failed validations and the updated_at timestamp in the database gets updated.)
On closer inspection, it seems that when I include a file_field in the form, it changes the form's behaviour when submitting blank text fields (probably due to the fact that form_for now outputs a form with enctype=-"multipart/form-data").
When the file_field isn't present, submitting a blank name sends these params to the server:
{ "id" => 1, "user" => { "name: "" }
Which results in something like User.find(1).update_attributes(name: "") in the controller, which of course fails to update because Rails sees that we're trying to update 'name' to a blank string and the validation fails.
When it is present, this gets submitted:
{ "id" => 1, "user" => { } (plus extra info about the avatar file)
The "name" key isn't present at all, so the controller runs User.find(1).update_attributes() which of course passes as there's nothing being updated that might fail a validation.
Is this a bug, or a feature? Why would changing the enctype to multipart (assuming that's the source of the problem) change the way blank text fields behave? (I've tested this in both Chrome and FF, fwiw.) If this is really the intended behaviour, how can I ensure that blank text fields get submitted properly without having to add a bunch of tedious boilerplate around every text field?
(If it matters, I'm using: Ruby 2.3.0, Rails 5.0.0.beta3, Paperclip 5.0.0.beta1, and I've tested in Chrome 49 and Firefox 45)
I had the same issue, updating Rails to the latest version fixed it.
I think you can do something like that
updated_user = User.new(your_params) # The new attributes is set to a new object record
target_user = User.find(params[:id]) # the user you want to update
target_user = updated_user
if target_user.save?
..
else
..
by this all the validations will be triggered and the active record will have all the new attributes, if the name is blank it'll catch it
The following strong param method won't bring back the dropped :name parameter, but it should prevent the form from imitating a successful submit:
private
def user_params
params.require(:user).permit(:name, :avatar)
end
This can be inserted as a private method under your Users Controller. Then simply call user_params in your Update method.

Navigation with Rails gem "acts-as-taggable-on"

I want to make an Navigation with specific Tags.
These Tags are for example: HTML, CSS and Javascript.
So when i click on one of them it will show all posts with these tag.
How can i achieve that?
My code for the Navigation right now looks like this (it's in the Application.html.erb)
<%= link_to "Computer", tag_list.Computer %>
I get this Error:
undefined local variable or method `tag_list' for #<#:0x007feec764ff88>
tag_list is a local variable or method, so unless you've created it in a helper that's your first issue. The second is that called .Computer on it doesn't work because tag_list is a method that created by the gem to list all an objects tags, and calling the . (also knowing as chaining) is attempting to call a method named Computer, which doesn't exist, that should just be a string and strings have to be quoted.
So, in your layout view, you can do
= link_to "Computer", tagged_posts_url(tag: "Computer")
Then in your posts_controller.rb add an action called tagged
def tagged
if params[:tag].present?
#posts = Post.tagged_with(params[:tag])
else
#posts = Post.all
end
end
To maintain a DRY set of views, you can even tell it to render the index view since you most likely already have a list of posts, now it will look exactly the same but only contain posts with that tag. e.g.
def tagged
if params[:tag].present?
#posts = Post.tagged_with(params[:tag])
else
#posts = Post.all
end
render "index"
end
Then in your config/routes.rb add a route for your new controller action under your existing post route
resources :posts do
collection do
get "/posts/tagged", as: :tagged
end
I got it myself.
Here is the Code:
<%= link_to 'Computer', { :controller => 'posts', :action => 'index', :tag => 'Computer'} %>
The controller looks like this:
def index
if params[:tag]
#posts = Post.tagged_with(params[:tag]).order('created_at DESC')
else
#posts = Post.all.order('created_at DESC')
end
end

Carrierwave can't save the image, using an engine

I'm learning to use Carrierwave the first step is obviously to upload a picture and see if it's effectively inserted to the database. One detail that could be important is that this code is written in a Rails Engine and namespaced (Wanker)
I generated an uploader following the instruction of the gem, everything went good (Wanker::PicturesUploader)
I made a model CompanyDetailImage with a picture string field (MySQL) and added this line
mount_uploader :picture, Wanker::PicturesUploader
Then I made a view and a form
<%= f.fields_for [:wanker, #company, #company_detail, #company_detail_images] %>
<%= i.label :picture %>
<%= i.file_field :picture %>
<% end %>
The params[:company][:company_detail_image]["picture"] in the controller will have this inside of it
[#<ActionDispatch::Http::UploadedFile:0x007fe613b81f40
#content_type="image/png",
#headers=
"Content-Disposition: form-data; name=\"company[company_detail_image][picture][]\"; filename=\"Screen Shot 2015-02-04 at 8.18.58 PM.png\"\r\nContent-Type: image/png\r\n",
#original_filename="Screen Shot 2015-02-04 at 8.18.58 PM.png",
#tempfile=# <File:/var/folders/2w/lw3glw5d58g25qvv4cx6yk0m0000gn/T/RackMultipart20150213-22947-np2et6>>]
Which for me seemed good. But when I try this
#company_detail_image = Wanker::CompanyDetailImage.new
#company_detail_image.picture = params[:company][:company_detail_image]["picture"]
#company_detail_image.save!
It returns this
ActiveRecord::RecordInvalid: Validation failed: Picture You are not allowed to upload nil files, allowed types: jpg, jpeg, gif, png
Does someone has an idea why it doesn't catch the picture ? Thank you guys ;)
Try this:
#company_detail_image.picture = params[:company][:company_detail_image]["picture"].first
This is because your ["picture"] param is returning an array rather than the object itself (which is the first item in that array).

.collect method get an error undefined method `collect' for nil:NilClass

I'm trying to have a drop down list but when i try it it give me
undefined method `collect' for nil:NilClass
the controller:
def existing
#courses = Course.all
end
def duplicate
course = Course.find_by_id(permitd_up[:id])
new_course = course.dup
if new_course.save
redirect_to :action => 'show'
else
redirect_to :back
end
end
the view:
<h3>Choose a Course</h3>
<%= form_for :course , url: {:action => "duplicate" , method: "post"} do |f|%>
<%= f.select :id , #courses.collect{|c| [c.id , c.name]} %>
<br><br>
<%= f.submit%>
<%end%>
You will receive the following error
undefined method `collect' for nil:NilClass
on
<%= f.select :id , #courses.collect{|c| [c.id , c.name]} %>
Only when #courses instance variable was not set in the action that rendered this particular view.
I see that #courses variable is set in the existing method. If you are using existing as an action which renders this view then your view name must be existing.html.erb.
Or if you are rendering the view from a different action then in that case you should set #courses value in that particular action by either directly setting the value within action OR by calling existing method from there.
If you have your courses as a database table, you might want to try using rails' built in field helper collection_select. It will populate your select field with all of the data available in your model. If you want a drop-down like the one you are describing, I believe using collection select is the best way to handle it.
You can read up on it here: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html
Alternatively, if you have a ton of courses, maybe try looking into using a text field with autocomplete. Jquery UI has a plugin that makes this very easy. You can check out the railscasts for it here: http://railscasts.com/episodes/102-auto-complete-association-revised.
It requires a pro account but if you do a lot of rails developing it will be the best $9 you spend every month.
If you would like to continue to do it this way, make sure that you are defining
#courses = Courses(:all) in the correct controller action, otherwise you will have nothing to render.

add comparison feature in rails

i'm having a bit of trouble with adding a certain feature. i'm working on a buy/sell site and i want to be able to compare posts. here's what i have so far:
in the posts view:
<%= button_to "Add to Compare", :action => "addCompare" %>
in the corresponding controller:
##a = Array.new()
def addCompare
##a << Post.id
end
so, all i want to do is add the post's id to the array ##a. when i test this, i click on the "Add to Compare" button and I'm welcomed with this:
Template is missing
Missing template posts/addCompare with {:locale=>[:en, :en], :formats=>[:html], :handlers=>[:rxml, :rjs, :builder, :rhtml, :erb]} in view paths "/home/mja32/470repo/traders/app/views", "/var/lib/gems/1.8/gems/devise-1.4.2/app/views"
So I guess it's trying to redirect to a view. How do I prevent it from doing this? All I want this button to do is to add the post's id to the array and nothing more.
Thanks in advance,
Matt
First of all, storing persistent data in a controller's class variable isn't going to work the way you want it to. There's no guarantee that ##a will be the same array on your next addCompare call; for example, your next addCompare call could be handled by a different process. Also, what happens if two different clients call addCompare? Do you really want to mix their data together in one pile? Probably not. Your first task is to replace ##a with a real per-user persistent store.
If you want to return nothing at all from your controller, just do this at the end of your controller method:
render :nothing => true, :status => :ok
That will tell Rails that something has already been rendered so it doesn't need to try the default rendering action (which is to render the posts/addCompare view) and returns nothing more than a 200 status code to the client.
Once that's in place, you'll probably want to AJAXify your button with :remote => true:
:remote - If set to true, will allow the Unobtrusive JavaScript drivers to control the submit behaviour. By default this behaviour is an ajax submit.
So this:
<%= button_to "Add to Compare", { :action => "addCompare" }, { :remote => true } %>
Note that button_to looks like this:
button_to(name, options = {}, html_options = {})
and that :action is for options but :remote is for html_options so you have to explicitly set up the hashes with {}; you could just wrap the options in braces:
<%= button_to "Add to Compare", { :action => "addCompare" }, :remote => true %>
but I prefer the consistency of wrapping them both by hand.