Rails: Template Error "dynamic constant assignment" - ruby-on-rails-3

In my view I render a partial.
The name of the partial is constructed by the name of a product page.
<%= render :partial => "product_pages/" + selected.headline %>
In the test case the headline is "electronics".
So I also tried:
<%= render :partial => "product_pages/electronics"
For testing the partial view looks like this:
<p>Test</p>
Now I get this error I do not understand:
ActionView::Template::Error (/var/www/*****/app/views/product_pages/_Elektro
nik.html.erb:1: dynamic constant assignment
...r = #output_buffer;Elektronik = local_assigns[:Elektronik];;...
... ^):
1: <p>Test</p>
app/views/pages/_content.html.erb:13:in `_app_views_pages__content_html_erb__4
0580468132849538_266915680_1201196437383914942'
app/views/pages/index.html.erb:3:in `_app_views_pages_index_html_erb__43007964
38685262523_267219620_562910368159856764'

You need to downcase your headline:
selected.headline.downcase
This is because you're going to be rendering a partial like this: product_pages/Elektronik, and when you call render :partial it'll attempt to define a local variable that has the same name as the partial, which is why you're getting this error: the code isn't defining a local variable but is actually defining a constant.
If you downcase it, it will define a local variable rather than this constant.

Related

Placing a span tag within an anchor in Haml

I am new to Haml and am trying to simply place a span tag within an anchor link like so:
.text Here is some copy.
= link_to 'Visit website', 'https://websitelink.com/', class: 'link'
%span
This is throwing an error, "syntax error, unexpected keyword_ensure, expecting $end"
How Do I perform this simple task?
Rails’ link_to helper accepts either the link text as a parameter or as the result of a block.
In this case you probably want something like this:
= link_to 'https://websitelink.com/', class: 'link' do
%span Visit website
Note the do indicating a block, and that there are only two parameters to the method, the “Visit Website” text has been moved into the block.
This renders:
<a class="link" href="https://websitelink.com/"><span>Visit website</span>
</a>

Display only one field from an embedded document with MongoID

I'm a real beginner with MongoDB and MongoID.
I created two scaffolds
class Objet
include Mongoid::Document
field :nom, type: String
embeds_one :coordonnee
end
And
class Coordonnee
include Mongoid::Document
field :adresse1, type: String
field :adresse2, type: String
field :code_postal, type: String
field :ville, type: String
embedded_in :objet
end
That's what I get when creating a new Objet :
Now, I'm trying to show only the field adresse1 for this document, but it doesn't work. I can display only the whole embedded document doing this :
When I do :
<%= #objet.coordonnees.adresse1 %>
I get this error :
undefined method `adresse1' for #<Hash:0x2b2b1f0>
How can I do that ?
EDIT
Doing that, I can display all the elements "Adresse1, adresse2, ville, code_postal" :
Controller
def show
#objet = Objet.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #objet }
end
end
View
<%= #objet.nom %>
<% #objet.coordonnee.each do |t| %>
<%= t[1] %>
<% end %>
But my question is : How to display ONLY one of them ? Such as ville, or code_postal or adresse1... ?
What was your code that works for the full document? It was dropped from your post.
In the mongo Shell, you could do this with dot notation db.collection.find({},{'coordonnees.adresse1':1,'_id':0}) You need to specify the '_id':0 because _id is always returned by default.
The other answer will not work because adresse1 is a subdocument. You must include the reference to coordonnees.
Not hugely familiar with MongoID, but assuming you can make calls straight to mongo, there is a second implicit parameter to all find-like statements called a projection that specifies what exactly you would like to return.
For instance, showing only adresse1 for all items in your collection:
db.collection.find({},{"coordonnees.adresse1": 1, "_id":0})
should return only the adresse1 parameter. I wasn't quite able to tell exactly what context you're displaying the objects in, but regardless of context, api calls to mongo should be fairly straightforward to make. Let me know if I've misinterpreted this question though.
In your posted example, you should change your find function to something like the following:
Objet.find({params[:id]}, {:fields => [coordonnees.adresse1]})
Hope that helps.
I found the solution to my problem.
To display only one element of the hash, I can do :
<%= #objet.coordonnees['adresse1'] %>
I am not sure if you are using embeds_one or embeds_many as you are using singular and plural forms of the relation name interchangeably in your question.
If it is a embeds_one the problem is that you should not iterate on #objet.coordonnee as it is a single document. Your view code should look like:
<%= #objet.nom %>
<%= #objet.coordonnee.address1 %>
If it is a embeds_many, your relation name should be plural, then you should be able to use t.address1 in your view.
# model Objet
embeds_many :coordonnees
# view
<%= #objet.nom %>
<% #objet.coordonnees.each do |t| %>
<%= t.address1 %>
<% end %>

Use translation for submit button

I don't want to use the default
<%= f.submit %>
and have created a helper function for it, which also embeds an icon. The helper function expects a label to put on the newly created button.
I'm calling it like this:
<%= submit_button("icon-plus", I18n.translate("helpers.submit.create")) %>
But now on this text appears on the button:
%{model} toevoegen
Instead of:
Product type toevoegen
If I use the normal submit button then the correct text appears so my yml files are correct. How can I get the correct text to use in the helper?
Helper code:
def submit_button(icon, label)
link_to "javascript:void(0)", :class => 'btn btn-primary', :onclick => "$(this).closest('form').submit()" do
raw('<div class="') + icon + raw(' icon-white"> ') + label +raw('</div>')
end
end
As the I18n guide says, the translate function interpolates variables passed in the %{} brackets using its second argument (a hash).
In your case you need to tell it the model by doing this:
I18n.t("helpers.submit.create", model: "Product type")
If you want a generic option that would work for any model, you can see how Rails itself does it by looking at the source on GitHub - it's something like
I18n.t("helpers.submit.create", model: f.object.class.model_name.human)
As an aside, you don't need to (and probably shouldn't) use raw there. What you are trying to achieve could easily be done with the built-in helpers:
link_to ... do
content_tag :div, label, class: "#{icon} icon-white"
end

Rails and named_scope queries

I'm trying to get my head around the concept of named_scoped queries in rails.
I'm trying to filter a table to get only non featured items (:featured => false).
In my model i have added
scope :allgames, where(:featured => false)
and
scope :featured, where(featured => true)
I'm trying to list all featured and non featured items separately on my Game index page.
Is it possible to to it via a named scope.
So far i have:
<% #games.each do |item| %>
<% if item.featured %>
<%= render 'application/item_synopsis_builder', item: item %>
<% end -%>
<% end %>
And I wonder if it is possible to do something like:
<% #games.featured.each do |item| %>
<%= render 'application/item_synopsis_builder', item: item %>
<% end %>
or
<%= render partial: 'application/item_synopsis_builder', collection: #games.featured %>
When I try I get a message saying that there is no method featured.
But when I run the command Game.featured in the console I get the result list of all featured games.
Is it possible to access this list/method in the view?
Named scopes are added to the model as a class method, so trying to access the method on a collection of objects won't work. Similar functionality can be achieved with:
#games.where(:featured => true).each do
...
end
But I would recommend having two variables in your controller:
#featured_games = Games.featured
#all_games = Games.allgames
then use those in your views.
Your views are driven by the #games instance variable that is created by the controller that is rendering the views. Named scopes create a class method for subclasses of ActiveRecord::Base. So "Game.featured" returns something because defining the named scope created a method for the Game class. It did not create an instance method that objects of the Game class (such as #games) can invoke. That's why "#games.featured" gives you an error.
To do what you want to do, create two instance variable in the controller and pass them to the view, e.g.
#all_games = Game.allgames
#featured_games = Game.featured
Both variables will be available to your view, and you can construct loops to render each collection however you like.
A scope is a class method (or assimilable to, I don't know the specifics), so yes, Game.featured would work, but when you do #games.featured, you are calling featured on an array of Game instances.

Rails 3 Rendering Binary Content

I need to render binary content(images) on web page. I'm saving images in the database with datatype binary. Now I need to iterate available images from the database and render on webpage.
Please check the below code that I'm doing. Icon is the image column name in material.
// iterating all materials
<% #materials.each do |material| %>
// for each material
<span><%= image_tag(material.icon) %></span>
<% end %>
Any help would be greatly appreciated..
You need to add an action to your controller along these lines (cribbed from here):
def image
#material = Material.find(params[:id])
send_data #material.icon, :type => 'image/png',:disposition => 'inline'
end
Then call the path to that action in your image_tag. You obviously need to make sure the :type field has the right MIME type, add a route, etc.